[Closed] CgTalk Maxscript Challenge 021: "More Information?"
CgTalk Maxscript Challenge 021: “More Information?”
DESCRIPTION: Create a tool that gives you more information about the scene than would normally be available. This can involve use of viewport drawing, a floating dialog, in-scene geometry, automated camera renders, or even an external file (HTML/XML/TXT etc).
The aim here is to flex your data-mining and information presentation skills (something every good TA should have!).
Try to think of information that would be useful to have on hand, either dynamically or for archive purposes.
DEADLINE: 30/10/2008
RULES:
[ul]
[li]Do NOT post your code until the deadline![/li][li]Code from scratch. Try not to use pre-exisitng functions or plugins.[/li][li]Show your script references, if any (eg. Looking at another script to assist you).[/li][li]You are encouraged to ask for help where needed, but try to do it on your own. The maxscript reference is an invaluable resource.[/li][li]Post your final script inside [/li]“`
tags (located on your posting toolbar).
[li]Post all code into THIS thread.[/li][li]Post the max version you coded in, plus any maxscript extensions you used. (Thanks galagast!)[/li][li]Try to finish the challenge in the proscribed time. There is no definite time limit.[/li][/ul]NOTES: Try to be creative with this one. Just exporting a text file of the summary info is not going to cut it!
erilaz,
I wanted to participate in the challenge, and started a small material-info tool. However, in the past week, the tool has grown a lot and proven to be really useful. Therefor, we’ve decided to keep it in-house for now and develop it further.
Thanks for the inspiration though, and maybe I’ll be able to publish it some day.
Excellent! The challenges are here for that purpose. Please share it if/when you can. The sharing of information is very important in the TD community.
sharing the outline of what a script does is sometimes as useful as sharing the whole thing now i’m curious! lol
LAME!
Just kidding of course Martijn, keep up the good work! Your scripting skills have improved a lot over the past year.
Cheers,
the other Martijn
That shouldn’t be a problem The main idea of the script is to check the map slots for all materials and collect these into an array. You can then filter this array in several ways and display them in a listView.
This way, you can easily find all materials that have a material in their reflection slot (for example), and disable/edit/delete them without ever opening the material editor. You can do this for multiple materials at the same time. You can also search materials/maps by name.
I’ve added a lot of options since the first version: for example, a filter to show all maps in the scene that have an output gamma that differs from your scene’s gamma setting (and have buttons to change it).
It might be useless for a lot of people, but I found it especially useful when cleaning up messy scenes.
magicm: Thanks, someone has to do it while you’re gone
Have you ever wondered what the “average” color in your scene is? NO!?..well… neither have I. BUT NOW YOU CAN KNOW!
Didn’t have a lot of free time, so instead of coding something useful I decided to code something fun…
(
fn averageColors colorArray = --returns the average color of an array of colors
(
local averageColor = color 0 0 0
FOR color in colorArray DO
(
averageColor = averageColor + color
)
averageColor = averageColor/colorArray.count
averageColor
)
local sceneArea = 0 --a variable to hold the sum of the area of every object in the scene
local objectAreaArray = #() --an array to hold of each individual object
FOR o in geometry DO
(
local numFaces = meshop.getNumFaces o.mesh --get the number of faces
local objectArea = 0
FOR faceIndex = 1 to numFaces DO
(
objectArea = objectArea + (meshop.getFaceArea o.mesh faceIndex) --get the object's full area by adding the faces
)
append objectAreaArray objectArea
sceneArea = sceneArea + objectArea --add all the objects to get the full scene area
)
local sceneColorsArray = #() --an array to hold the colors to be averaged
global objectColorsArray = #() --an array to hold the object's individual color to be used by the select button
FOR objectIndex = 1 to geometry.count DO --collect all colors
(
IF geometry[objectIndex].material == undefined THEN --use the wirecolor for objects without a material
(
local percentArea = (objectAreaArray[objectIndex]/sceneArea as integer)*100 --find which percentage of the total scene area this object holds
FOR x = 1 to percentArea DO --add one color item to sceneColorsArray per percentage point
(
append sceneColorsArray geometry[objectIndex].wirecolor
)
append objectColorsArray geometry[objectIndex].wirecolor
)
ELSE
(
IF (classOf geometry[objectIndex].material) == Standardmaterial DO --only consider objects with standard materials (too lazy to code special cases, sorry)
(
IF geometry[objectIndex].material.diffusemap != undefined THEN --use the texture map in the diffuse channel if it exists
(
local tempMap = renderMap geometry[objectIndex].material.diffuseMap size:[20,20] scale:200 --render a sample of the texture map
local pixelArray = #()
FOR bitmapRow = 0 to 19 DO --collect the pixels from the rendered sample
(
local rowArray = getPixels tempMap [0,bitmapRow] 20
FOR pixel in rowArray DO append pixelArray pixel
)
local averageColor =averageColors pixelArray --average the colected pixels
local percentArea = (objectAreaArray[objectIndex]/sceneArea as integer)*100 --find which percentage of the total scene area this object holds
FOR x = 1 to percentArea DO --add one color item to sceneColorsArray per percentage point
(
append sceneColorsArray averageColor
)
append objectColorsArray averageColor
)
ELSE --if no texture map exists in the difuse channel use the diffuse color
(
local percentArea = (objectAreaArray[objectIndex]/sceneArea as integer)*100 --find which percentage of the total scene area this object holds
FOR x = 1 to percentArea DO --add one color item to sceneColorsArray per percentage point
(
append sceneColorsArray geometry[objectIndex].material.diffuse
)
append objectColorsArray geometry[objectIndex].material.diffuse
)
)
)
)
local averageColor
IF sceneColorsArray.count > 0 DO --find the average color from all the colors collected
(
averageColor = averageColors sceneColorsArray
)
rollout ColorFinder "Color Finder"
(
label label01 "This scene's average color is:"
bitmap theColorBitmap align:#left width:80
label label02 "R :" pos:(theColorBitmap.pos+[90,10]) align:#left
label label03 "G :" pos:(label02.pos+[0,30]) align:#left
label label04 "B :" pos:(label03.pos+[0,30]) align:#left
label label05 "H :" pos:(label02.pos+[65,0]) align:#left
label label06 "S :" pos:(label05.pos+[0,30]) align:#left
label label07 "V :" pos:(label06.pos+[0,30]) align:#left
group "Select by Color"
(
colorpicker theColorPicker width:50 height:50
spinner theSpinner "Threshold : " pos:(theColorPicker.pos+[65,5]) fieldWidth:50 range:[0,255,75] type:#integer
button isolateButton "Select" width:125 height:20 pos:(theColorPicker.pos+[65,30])
)
ON isolateButton pressed DO
(
clearSelection()
targetColor = theColorPicker.color
threshold = theSpinner.value
FOR colorIndex = 1 to objectColorsArray.count DO
(
IF objectColorsArray[colorIndex].r <= (targetColor.r+threshold) AND objectColorsArray[colorIndex].r >= (targetColor.r-threshold) AND
objectColorsArray[colorIndex].g <= (targetColor.g+threshold) AND objectColorsArray[colorIndex].g >= (targetColor.g-threshold) AND
objectColorsArray[colorIndex].b <= (targetColor.b+threshold) AND objectColorsArray[colorIndex].b >= (targetColor.b-threshold)
DO selectmore geometry[colorIndex]
)
)
)
createDialog ColorFinder 240 190
colorFinder.theColorBitmap.bitmap = (bitmap 1 1 color:averageColor)
colorFinder.label02.text = "R :"+(averageColor.r as integer) as string
colorFinder.label03.text = "G :"+(averageColor.g as integer) as string
colorFinder.label04.text = "B :"+(averageColor.b as integer) as string
colorFinder.label05.text = "H :"+(averageColor.h as integer) as string
colorFinder.label06.text = "S :"+(averageColor.s as integer) as string
colorFinder.label07.text = "V :"+(averageColor.v as integer) as string
)
The script will check all the objects in the scene and sample their average color (if it has a material applied it will render a small sample of the diffuse channel and average the pixels). Then the colors will be added to an array and averaged once again to get the overall scene color…pretty cool eh? (NOT!)
The script takes into account the surface area of the surface objects, that means that BIGGER objects will have more influence in the end result. This in turn means that the script has to calculate the area for every object in the scene which normally takes a prohibitive amount of time. So it’s useless AND slow!!
Finally I also added a few controls to allow the user to select items on the scene by their average color. Just set the color you wish to select and set the threshold according to your liking.
ENJOY!
hahaha, useless AND slow
actually i can imagine the above feature to be useful in some special situations. does this also consider maps like the rest of the script?
Might be nice to create an “Start” button in your interface, instead of running the tool on evaluation.
I evaluated the script in a medium sized scene and it immediately crashed max with a memory error
Yes it does, however the script only works with standard materials. It could easily expanded to support other shaders… but what’s the point right?
It’s not a bug, it’s a feature…. I find it works best on scenes with less than 3 objects…
well, then it’s 100% useless for me… in other words: this script totally fits my needs
this script is useful for preview scene and when you want obtain Focus plane in Depth of Field
hey guys i read this thread and it gave me the idea to make a lil properties lister… nothing fancy but imo usefull for scripters.
try(closeRolloutFloater InfoRO)catch()
sleep 0.1
CurSelection=""
fn UpdateInfo = ()
rollout Stats "Statistics" (
label TriCountlbl "Triangle Count . . . . ." width:90 pos:[180,5]
label Tricount "NIL" width:90 pos:(TriCountlbl.pos+[80,0])
label VertCountlbl "Vertex Count . . . . ." width:90 pos:(TriCountlbl.pos+[0,17])
label Vertcount "NIL" width:90 pos:(VertCountlbl.pos+[80,0])
label Class1lbl "Class . . . . . . . . . ." width:90 pos:[5,5]
label Class1 "NIL" width:90 pos:(Class1lbl.pos+[80,0])
label SuperClass1lbl "SuperClass . . . . ." width:90 pos:(Class1lbl.pos+[0,17])
label SuperClass1 "NIL" width:90 pos:(SuperClass1lbl.pos+[80,0])
)
rollout InfoLister "Maxscript Properties" (
pickbutton pck "Pick Object"
edittext MSProperties "Class" width:190 height:18 pos:[20,35]
edittext NodeProperties "Node" width:190 height:18
edittext ModProperties "Mods" width:230 height:18 pos:(MSProperties.pos+[(MSProperties.width+15),0])
on InfoLister open do (
UpdateInfo()
InfoLister.NodeProperties.pos=(MSProperties.pos+[0,(MSProperties.height+15)])
InfoLister.height=(InfoLister.MSProperties.height+InfoLister.NodeProperties.height+60)
)
on pck picked obj do(
Curselection=obj
UpdateInfo()
select obj
InfoLister.NodeProperties.pos=(MSProperties.pos+[0,(MSProperties.height+15)])
)
)
InfoRO = newRolloutFloater "Informator" 480 190
addRollout Stats InfoRO
addRollout InfoLister InfoRO
fn UpdateInfo = (
if Curselection != undefined and CurSelection != "" do(
if (SuperClassOf CurSelection) == GeometryClass then(
--TriCount
Stats.TriCount.text=(GetNumfaces CurSelection.mesh)as string
--VertCount
Stats.VertCount.text=(GetNumVerts CurSelection.mesh)as string
)else(
--TriCount
Stats.TriCount.text=0 as string
--VertCount
Stats.VertCount.text=0 as string
)
--ClassOf
Stats.Class1.text=(classof CurSelection)as string
--SuperClassOf
Stats.SuperClass1.text=(superclassof CurSelection)as string
--MaxScript Properties
local MSProps="" as stringstream
InfoLister.MSProperties.height=18
for i in (getPropNames CurSelection) do (
i=("#" + (i as string))
local MSProps2=replace (i as string) 1 1 "$."
format "%
" MSProps2 to:MSProps
InfoLister.MSProperties.height=InfoLister.MSProperties.height+12
)
InfoLister.MSProperties.text= MSProps
--Node Properties
local MSProps="" as stringstream
InfoLister.NodeProperties.height=18
for i in (getPropNames (classof(superclassof CurSelection))) do (
i=("#" + (i as string))
local MSProps2=replace (i as string) 1 1 "$."
format "%
" MSProps2 to:MSProps
InfoLister.NodeProperties.height=InfoLister.NodeProperties.height+12
)
InfoLister.NodeProperties.text= MSProps
--modifiers Properties
local MSProps="" as stringstream
InfoLister.ModProperties.height=18
for i in (CurSelection.modifiers) do (
for L in (getPropNames i) do(
L=("#" + (L as string))
local MSProps2=replace (L as string) 1 1 ("$.modifiers[#"+i.name+"]." )
format "%
" MSProps2 to:MSProps
InfoLister.ModProperties.height=InfoLister.ModProperties.height+12
)
)
InfoLister.ModProperties.text= MSProps
)
try(InfoLister.height=(InfoLister.MSProperties.height+InfoLister.NodeProperties.height+60) )catch()
)