[Closed] MS + DotNet MultiThreading with objects creation
Hi,
I was wondering if it was possible to run a maxscript in multithreading with DotNet ( with BackgroundWorker ) and creating objects, moving, adding modifiers on them ?
I was trying with this, but it seems to crash max all the time :
myThreads = #()
fn doSomeStuff =
(
for i = 1 to 10000 do Box lengthsegs:1 widthsegs:1 heightsegs:1 length:10 width:10 height:10
print "done"
)
for i = 1 to 8 do
(
myThreads[i] = dotNetObject "system.componentModel.backgroundWorker"
dotnet.addEventHandler myThreads[i] "DoWork" doSomeStuff
myThreads[i].runWorkerAsync()
)
Thank you for your help
I can be done indirectly… but you’ll loose any advantages of multi threading and it’s not very efficient but for small things it works great.
If you create a global array onto which you can push strings of maxscript from your backgroundworker thread you can execute those strings in the main thread via a execute command in dotnet timer like so:
script_queue=#()
fn scanScript = (
if (script_queue.count>0) do
(
scr=script_queue[1];
deleteItem script_queue 1
try(
execute scr[1]
) catch
(
print "**MXS ERROR**"
)
)
)
scriptExecuter = dotNetObject "System.Windows.Forms.Timer"
dotnet.addEventHandler scriptExecuter "tick" scanScript
scriptExecuter.interval = 100
scriptExecuter.start()
Thank you Jonadb, your solution seems to be for heavy calculation beside little maxscript viewport operation, is it ?
In fact my script run through all the vertex of an object ( and through the timeline) and it create a plane on each vertex ( with normal orientation), then i add on each modifiers and finally at the end of the frame it convert all the separate plane into a single edit poly. Then next frame is started.
I was thinking about cutting the timeline and then calling through DotNet 8 times 3ds max (1 per thread) and running the script, and finally regrouping the resulting geometry inside the same max.
I could be of use for heavy calculations with little output but ‘m using it for socket communications. A background thread receives maxscript commands via TCP/IP that needs to be executed in the main thread via above method.
One tip for combining a bazilion small object into one mesh… Abuse ProBoolean in ‘attach’ mode, it doesn’t alter geometry just attached everything into on big mesh very quickly.
Small example where $main if your base mesh
for obj in selection do
(
ProBoolean.SetOperandB $main obj 4 0
)
Then you can either collapse that to editmesh/poly or jsut leav it as proboolean object. I use this for a cloud script and it does 20000 planes in a few seconds.
Maybe I’m wrong but according to mxs help there is no addmethod 4
<void>SetOperandA boolnode
<void>SetOperandB boolnode node addMethod matMethod
The third argument is an integer controlling the operation to be performed and corresponding to the radio button state in the UI. Possible values are:
0 -Union
1 -Intersection
2 -Subtraction
3 -Merge
The fourth argument is an integer defining the method to add operands B, corresponding to the radio button state in the UI. Possible values are:
0 -Reference
1 -Copy
2 -Move
3 -Instance
The fifth argument is an integer controlling the material mdethod and corresponding to the radio button state in the UI. Possible values are:
0 -Apply Operand Method
1 -Retain Original Material
Can you show a small example of your method.
Ok, thank you for the tips about the proboolean works great !
I keep searching about launching other 3ds max, opening the same scene , starting the same script but with other frame to perform.
Ps : I don’t get if you pass through TCP/IP to start things on the same computer or if you use it to start things through network
See this video for an early prototype of what I’m building in my spare time where the snippet is from: http://vimeo.com/47002666
With ‘shelllaunch’ you can start any program, including max.
Waht you could do is save your scene 8 times, each with a different name that includes a framerange but before you do that set a startupscript that extracts the frameranges from the filenames and starts the calculation for them after which it automatically saves the file.
So you get 8 files like this:
file_0_200.max
file_201_400.max
etc
Start Max via shelllaunch, each loading a different file… the startup script kicks in and performs the operation on set ranges and saves when done. Merge results into on file and you’re done
edit: sorry, not in a startup script directly but make a startup script that sets an ‘filePostOpen’ eventhandler which performs the calculations…
It’s a secret method But you can see them UI for ProBoolean, just count the radio button starting at 0, somehow 4 and 5 aren’t listen in the docs.
0=Union
1=Intersection
2=Subtraction
3=Merge
4=Attach <= this is what we want
5=Insert
Very nice. I did not know about that.
And how can I perform this “attach” method in this example if is not a secret
delete objects
shift = on
tea = teapot radius:10 name:"main"
for z = 0 to 9 do
(
shift = not shift
for x = 0 to 9 do
(
main = (copy $main)
main.pos = if shift then [30*x,0,20*z] else [10+30*x,0,20*z]
in coordsys local main.rotation = (random (eulerAngles 0 0 0) (eulerAngles 0 0 359))
main.wirecolor = (clr = random black white ; clr.s = 255. ; clr)
)
)
delete $main
ProBoolean.SetOperandA $.main001
-- . . . ???
Like so:
delete objects
shift = on
teamain = teapot radius:10 name:"teamain"
ProBoolean.createBooleanObject $teamain undefined 4 1 0 --create master boolean with no operant B (undefined)
tea = teapot radius:10 name:"sub"
for z = 0 to 9 do
(
shift = not shift
for x = 0 to 9 do
(
sub = (copy $sub)
sub.pos = if shift then [30*x,0,20*z] else [10+30*x,0,20*z]
in coordsys local sub.rotation = (random (eulerAngles 0 0 0) (eulerAngles 0 0 359))
sub.wirecolor = (clr = random black white ; clr.s = 255. ; clr)
ProBoolean.SetOperandB $teamain sub 4 0 -- keep adding B operands
)
)
Hey Jonathan,
your attach method is very fast!
This is the test on the Teapot Wall
#1 TEST
(
delete objects
shift = off
geo = Editable_Mesh transform:(matrix3 1) wirecolor:yellow name:"teamain"
ProBoolean.createBooleanObject $teamain undefined 4 1 0 --create master boolean with no operant B (undefined)
tea = teapot radius:10 name:"sub"
gc()
t1 = timestamp()
m1 = heapfree
for z = 0 to 19 do
(
shift = not shift
for x = 0 to 19 do
(
sub = (copy $sub)
sub.pos = if shift then [30*x,0,20*z] else [10+30*x,0,20*z]
in coordsys local sub.rotation = (random (eulerAngles 0 0 0) (eulerAngles 0 0 359))
ProBoolean.SetOperandB $teamain sub 4 0 -- keep adding B operands
)
)
delete $sub
format "time:% memory:%
" ((timestamp()- t1 as float)/1000) (m1-heapfree)
)
The result > time:0.328 memory:224184L
#2 TEST
(
delete objects
shift = off
geo = Editable_Mesh transform:(matrix3 1) wirecolor:yellow name:"teamain"
tea = teapot radius:10 name:"sub"
gc()
t1 = timestamp()
m1 = heapfree
for z = 0 to 19 do
(
shift = not shift
for x = 0 to 19 do
(
sub = (copy $sub)
sub.pos = if shift then [30*x,0,20*z] else [10+30*x,0,20*z]
in coordsys local sub.rotation = (random (eulerAngles 0 0 0) (eulerAngles 0 0 359))
attach geo sub
)
)
delete $sub
format "time:% memory:%
" ((timestamp()- t1 as float)/1000) (m1-heapfree)
)
The result > time:24.684 memory:224184L
Huge difference in speed.
Thanks again for this example.
you do wrong test for the performance…
the ProBoolean attach method is much slower then smart poly attach and much more expensive for memory use.
here is true test:
fn makeNodes offset:[0,0,0] wirecolor:orange clean:on =
(
if clean do delete objects
nodes = #()
for y=0 to 9 do for x=0 to 9 do
(
b = box width:10 length:10 height:10 widthSegs:10 lengthSegs:10 heightSegs:10 pos:([x*12,y*12,0] + offset) wirecolor:yellow
append nodes (converttopoly b)
)
s = box width:20 length:20 height:20 pos:([-20,0,0] + offset) wirecolor:wirecolor
#(converttopoly s, nodes)
)
fn clusterAttach source nodes =
(
k = 1
insertitem source nodes 1
count = nodes.count
attach = polyop.attach
while nodes.count > 1 and not keyboard.escpressed do
(
attach nodes[k] nodes[k+1]
deleteItem nodes (k+1)
k += 1
if (k+1) > nodes.count do k = 1
)
nodes[1]
)
fn booleanAttach source nodes =
(
ProBoolean.createBooleanObject source undefined 4 1 0
for k=1 to nodes.count while not keyboard.escpressed do
(
ProBoolean.SetOperandB source nodes[k] 4 0
)
converttopoly source
source
)
max create mode
(
d = makeNodes offset:[0,0,25] wirecolor:brown clean:on
gc()
t1 = timestamp()
m1 = heapfree
booleanAttach d[1] d[2]
format "boolean >> time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
)
(
d = makeNodes offset:[0,0,0] wirecolor:orange clean:off
gc()
t1 = timestamp()
m1 = heapfree
clusterAttach d[1] d[2]
format "cluster >> time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
)