CGTalk > Software > Autodesk 3ds max > 3dsMax SDK and MaxScript
Login register
Thread Closed share thread « Previous Thread | Next Thread »
 
Thread Tools Search this Thread Display Modes
Old 06-10-2011, 01:15 AM   #1
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
when transform changes

Hey guys!

So I was looking for a quite specific callback mechanism. The "when transform changes" construct is pretty close but not exactly what I need.
The construct allows me to run code "while" objects are being transformed. (It is quite a lot of code that I need to run, I need to basically put the transform properties in arrays of every object in the selection. So this causes quite a lot of lag when you move the objects around.)

I would rather prefer a callback mechanism that let's me run code only after it has stopped moving. I'm pretty sure there is nothing like that in 3dsMax, I might be wrong though.

So I suspect I might have to live with "when transform changes" and combine it with a timer perhaps? Not sure how... maybe I can use the construct to notify me that the objects are being transformed, and maybe a timer that checks how long ago the last transformation was done, and if it was 500ms ago... it runs the code! I still wouldn't know how to "connect" the timer with the construct so that the timer "knows" how long ago the the construct ran. arhgh Does this make any sense?

Do you guys have any ideas?
 
Old 06-10-2011, 02:04 AM   #2
eek
Fixer
 
eek's Avatar
portfolio
Charles Looker
Snr Technical Artist
Electronic Arts
Vancouver, Canada
 
Join Date: Feb 2002
Posts: 4,221
Use a dotNetTimer and event:

http://forums.cgsociety.org/showthr...ht=dotnet+event
http://forums.cgsociety.org/showthr...ht=dotnet+timer

You could do something like when the transform of the selection changes a count get appended. If the count doesnt change for 40ms or so append the array. You could set a flag to false as well to only append the array once - then when you transform the objects again the flag gets set to true.

roughly..
__________________
Disclaimer: My opinions are not those of my employer.


 
Old 06-10-2011, 05:29 AM   #3
denisT
MAX Doctor
 
denisT's Avatar
portfolio
Denis Trofimov
CA, USA
 
Join Date: Jul 2009
Posts: 9,508
Send a message via ICQ to denisT
Quote:
Originally Posted by Norman3D
So I was looking for a quite specific callback mechanism. The "when transform changes" construct is pretty close but not exactly what I need.
The construct allows me to run code "while" objects are being transformed. (It is quite a lot of code that I need to run, I need to basically put the transform properties in arrays of every object in the selection. So this causes quite a lot of lag when you move the objects around.)


as i understood your problem, the way of getting transforms of many objects is too slow for your needs. is it correct?
but to collect transforms of 10,000 objects takes less than 0.1s... is it slow? it's less that screen redraw time.
i'm not sure that you use the when construct the right way.
 
Old 06-10-2011, 12:25 PM   #4
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
Ok, so I'm just going to explain what it is that I'm working on...
I'm working on a little tool that allows artists to place objects in 3dsMax and then move them to Unreal Engine 3.
The reason for this is that Unreal 3 does not have many placement tools. So in 3dsMax you could for example use reactor to let a couple of boxes fall, whereas in Unreal you would have to place each one of them manually. So right now I have the "useful" part working. You click on a button and ta-da! You have your assets placed in Unreal.

But I'm working on another feature, just for fun. I don't really think it has practical use. But I'd like to see how fast I can get it to work. I want to try to achieve 1:1 sync between the two programs.

Watch this: http://www.youtube.com/watch?v=nnfdj5VVVjs

(Notice how it lags in 3dsMax when you move only 30 objects, this is because of my when construct)

So there is no real mystery as to how I pass the objects to Unreal. You can select one of the objects in Unreal, Crtl-C and paste it in the script. The contents of the clipboard have properties about the object, such as name, location, rotation, and scale.

So this is how I have it setup:
The when transform changes construct adds the location, rotation, scale to global arrays.
Then there is a dotnetTimer set to 500ms that checks those variables and creates the new clipboard text and finally sends a Crtl-V to the Unreal window.

While I'm writing this, I realize I might be doing a bit too much in the when construct...

Code:
when transform selection changes id:#UDK_TRANSFORM_TRACKER do ( global theUDK_LOCATIONS = #() global theUDK_ROTATIONS = #() for n in theOBJECTselection do ( theNewLocation = ("Location=(X=" + (n.pos[2] as string) + "," + "Y=" + (n.pos[1] as string) + "," + "Z=" + (n.pos[3] as string) + ")") pitch = ((n.rotation.controller[1].value * 182) as integer) as string yaw = ((((n.rotation.controller[3].value * -1) * 182) as integer) as string) roll = ((n.rotation.controller[2].value * 182) as integer) as string theNewRotation = ("Rotation=(Pitch=" + pitch + "," + "Yaw=" + yaw + "," + "Roll=" + roll + ")") append theUDK_LOCATIONS theNewLocation append theUDK_ROTATIONS theNewRotation ) )


I'm already preparing the lines that need to be added to the final output text that the Timer takes care of. Do you think I should get rid of that part, and just add the raw data to the array and let the Timer take care of creating the final string?

So what I would need is to either get the when construct to be faster! Or think of an alternative callback mechanism, that notifies me when objects have stopped moving.

(Btw, offtopic: I also realized that the SetClipboardText took 5 seconds compared to the dotnet alternative that only takes 0.003 seconds! What the hell? )

Edit: To clarify: "theOBJECTselection" is also a global array set by a dialog. The user has to select first which objects in the scene will be synced, so that's what the array contains.

Last edited by Norman3D : 06-10-2011 at 12:27 PM.
 
Old 06-10-2011, 01:20 PM   #5
Pjanssen
Veteran
portfolio
Pier Janssen
Göteborg, Sweden
 
Join Date: Apr 2003
Posts: 2,400
You could start/reset the timer in the when clause, and do all the performance-heavy stuff when the timer ticks. That way the timer would only tick after there have been no transformations for the specified timer delay.
You might have to take a bit of care to make sure nothing funky happens if you quickly change and transform the selection though.

And in general: do performance tests on your code (http://forums.cgsociety.org/showthr...p?f=98&t=981125) and on parts of it. Add traces to see how often blocks are being executed. Find the bottleneck and focus on optimizing that

Last edited by Pjanssen : 06-10-2011 at 01:23 PM.
 
Old 06-10-2011, 01:26 PM   #6
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
Quote:
Originally Posted by Pjanssen
You could start/reset the timer in the when clause, and do all the performance-heavy stuff when the timer ticks. That way the timer would only tick after there have been no transformations for the specified timer delay.
You might have to take a bit of care to make sure nothing funky happens if you quickly change and transform the selection though.

And in general: do performance tests on your code (http://forums.cgsociety.org/showthr...p?f=98&t=981125) and on parts of it. Add traces to see how often blocks are being executed. Find the bottleneck and focus on optimizing that


aha! That makes sense! What about stopping the when construct at some point in the Timer? Then wait until it has finished running the heavy stuff and start the when construct again. I'll give this a try... Thanks!
 
Old 06-10-2011, 01:30 PM   #7
Pjanssen
Veteran
portfolio
Pier Janssen
Göteborg, Sweden
 
Join Date: Apr 2003
Posts: 2,400
Yes you could do more 'fixed' periodic updates too. With either approach, I'd say don't generate or process data in the when clause unless you will actually use it.
 
Old 06-10-2011, 03:44 PM   #8
denisT
MAX Doctor
 
denisT's Avatar
portfolio
Denis Trofimov
CA, USA
 
Join Date: Jul 2009
Posts: 9,508
Send a message via ICQ to denisT
when construct is not an issue in your case. it can't cause the delay. the delay is caused by the way how you transfer data from MAX to UNREAL.
check the when using sample:
Code:
deleteAllChangeHandlers id:#udk_transform_tracker csb = dotnetclass "System.Text.StringBuilder" srt_obj = "NodeName={0}" srt_pos = "Location=(X={1},Y={0},Z={2})" srt_rot = "Rotation=(Pitch={0},Yaw={2},Roll={1})" global _udk_nodenames = #() global _udk_locations = #() global _udk_rotations = #() fn _udk_GetTransform node = ( sb = dotnetobject csb sb.AppendFormat srt_obj node.name append _udk_nodenames (sb.ToString()) sb = dotnetobject csb sb.AppendFormat srt_pos node.pos[1] node.pos[2] node.pos[3] append _udk_locations (sb.ToString()) sb = dotnetobject csb sb.AppendFormat srt_rot (node.rotation.controller[1].value*182) (-node.rotation.controller[3].value*182) (node.rotation.controller[2].value*182) append _udk_rotations (sb.ToString()) ) when transform objects changes id:#udk_transform_tracker handleAt:#redrawViews node do _udk_GetTransform node

it's fast enough

if you want to check transform data history:
Code:
fn _udk_GetNodeInfo index: = ( if index == unsupplied do index = _udk_nodenames.count if index > 0 and index <= _udk_nodenames.count do format "%\n\t%, %\n" _udk_nodenames[index] _udk_locations[index] _udk_rotations[index] )


You might meet a problem very soon using string arrays. With you method max memory leaks very quick. I would make some c# DLL and send data (obj name + transform (float arrays)) to the .net object. The .net object would transfer data to UNREAL. Technically it might be in another thread. so you can collect of transforms and send data to unreal asynchronously.
 
Old 06-10-2011, 07:34 PM   #9
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
First of all thanks denis once more for your help!

Quote:
Originally Posted by denisT
when construct is not an issue in your case. it can't cause the delay. the delay is caused by the way how you transfer data from MAX to UNREAL.


I did a test where I'm not transferring the data to Unreal, just running the when construct passing the transform values to the arrays and it was lagging just as much! So I don't think it has anything to do with the transferring.

Regarding your code...
What is the difference between using 3dsMax arrays and "dotnetclass "System.Text.StringBuilder"". Is this StringBuilder still an array? Is it faster because I'm only working with dotnet instead of working with 3dsMax arrays?


About transferring data to Unreal, since you mentioned this as being the bottleneck... I did a quick test and it takes around 0.29 seconds to transfer. Of those 0.29 seconds, it takes 0.25 to send the keystrokes. I think it takes that much time, because I'm actually sending a "delete" key before pasting the output. And it takes around 0.25 seconds to delete the selection in Unreal. There is not much I can do about that, though :/
It would be awesome if I could actually connect 3dsMax with Unreal, so that I could have access to the objects placed in the scene, and move them, instead of deleting and placing them again.

Quote:
Originally Posted by denisT
You might meet a problem very soon using string arrays. With you method max memory leaks very quick. I would make some c# DLL and send data (obj name + transform (float arrays)) to the .net object. The .net object would transfer data to UNREAL. Technically it might be in another thread. so you can collect of transforms and send data to unreal asynchronously.


Hmmm... could you give me an estimate as to how much 3dsMax can handle? I'm not planning on transferring 10000 objects. So if the leaking would occur around that number it wouldn't be a problem. But it does happen, haha I'm afraid I'm going to have to learn to create DLLs.

Another question. How do I properly convert an array to a string?
Would this be the fastest way? Probably not...

Code:
theArray = #("test1", "test2") TheString = "" for n in theArray do ( theString = theString + "\n" + n )
 
Old 06-10-2011, 07:43 PM   #10
denisT
MAX Doctor
 
denisT's Avatar
portfolio
Denis Trofimov
CA, USA
 
Join Date: Jul 2009
Posts: 9,508
Send a message via ICQ to denisT
what does the unreal actually need? what do you send to the unreal? as I know it should be a string...
 
Old 06-10-2011, 07:47 PM   #11
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
yes exactly. Here is an example:

Code:
Begin Map Begin Level Begin Actor Class=StaticMeshActor Name=StaticMeshActor_4143 Archetype=StaticMeshActor'Engine.Default__StaticMe shActor' Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0 ObjName=StaticMeshComponent_560 Archetype=StaticMeshComponent'Engine.Default__Stat icMeshActor:StaticMeshComponent0' StaticMesh=StaticMesh'LT_Buildings2.SM.Mesh.S_LT_B uildings_SM_BunkerSupA2' OverriddenLightMapRes=32 ReplacementPrimitive=None PreviewEnvironmentShadowing=51 bAllowApproximateOcclusion=True bForceDirectLightMap=True bUsePrecomputedShadows=True BlockNonZeroExtent=False BlockRigidBody=False LightingChannels=(bInitialized=True,Static=True) Name="StaticMeshComponent_560" ObjectArchetype=StaticMeshComponent'Engine.Default __StaticMeshActor:StaticMeshComponent0' CustomProperties End Object StaticMeshComponent=StaticMeshComponent'StaticMesh Component_560' Components(0)=StaticMeshComponent'StaticMeshCompon ent_560' Location=(X=464.000000,Y=1632.000000,Z=-672.000000) Rotation=(Pitch=-4096,Yaw=0,Roll=0) DrawScale=2.000000 CollisionType=COLLIDE_BlockWeapons BlockRigidBody=False CreationTime=12.641472 Tag="StaticMeshActor" CollisionComponent=StaticMeshComponent'StaticMeshC omponent_560' Name="StaticMeshActor_4143" ObjectArchetype=StaticMeshActor'Engine.Default__St aticMeshActor' End Actor End Level Begin Surface End Surface End Map
 
Old 06-10-2011, 07:59 PM   #12
Pjanssen
Veteran
portfolio
Pier Janssen
Göteborg, Sweden
 
Join Date: Apr 2003
Posts: 2,400
Quote:
Originally Posted by Norman3D
What is the difference between using 3dsMax arrays and "dotnetclass "System.Text.StringBuilder"". Is this StringBuilder still an array? Is it faster because I'm only working with dotnet instead of working with 3dsMax arrays?
The StringBuilder is a class designed specifically for performing string operations (concatenating for example). Underneath it uses a char array. It is probably faster than using a normal String object when performing many operations on a string. And probably faster than using maxscript arrays too. But as with everything, it really depends on the situation, and the only proof you can get is by benchmarking it. For example, .NET calls might end up costing more than they gain.

Quote:
Hmmm... could you give me an estimate as to how much 3dsMax can handle? I'm not planning on transferring 10000 objects. So if the leaking would occur around that number it wouldn't be a problem. But it does happen, haha I'm afraid I'm going to have to learn to create DLLs.
I think there can be a short answer to that: memory leaking is always bad.
 
Old 06-10-2011, 08:49 PM   #13
denisT
MAX Doctor
 
denisT's Avatar
portfolio
Denis Trofimov
CA, USA
 
Join Date: Jul 2009
Posts: 9,508
Send a message via ICQ to denisT
Quote:
Originally Posted by Norman3D
yes exactly. Here is an example:

Code:
Begin Map ... End Map

does it mean you send a file of this format?
 
Old 06-11-2011, 12:19 AM   #14
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
Quote:
Originally Posted by denisT
does it mean you send a file of this format?

This wouldn't be really a file. It's just text in the clipboard that is being pasted on the Unreal 3 Viewport. It contains all the relevant data. It references an asset in the asset library and all sorts of different properties. Unreal then knows what to do with the pasted text.
So you can basically select an object in a Unreal scene copy and paste it in notepad. And do any kind of changes to it, (not to the geometry obviously), but you can change values such as the transformation values.
This is what I'm basically doing with the script. I really don't think that the creation of the text file is the bottleneck. (Besides the possible memory leaking you guys mentioned.) But in terms of speed, it only took around 0.05 seconds to create the output text (30 objects).

My main concern was the "when construct" that is definitely slowing things down. But as Pjanssen suggested, I could simply start and stop the timer in the when construct. And then let the timer do the parsing and creation of the output text when it gets enough time. In other words, when the objects have stopped moving.
 
Old 06-12-2011, 01:26 AM   #15
Norman3D
Frequenter
 
Norman3D's Avatar
portfolio
Norman Schaar
3D Artist
España
 
Join Date: Feb 2005
Posts: 221
Ok quick update! Pjanssen's idea about stopping and starting the timer in the when construct worked very well! It is exactly what I was looking for.

However it was still lagging a bit. I did a little test where I printed the objects position in the when construct and I realized that a position is always printed twice. So I "optimized" the when construct a bit.

Code:
global tick = 1 when transform selection changes id:#UDK_TRANSFORM_TRACKER do ( if tick == 1 then ( tick = 2 ) else ( UDK_theTimer.stop() UDK_theTimer.start() tick = 1 ) )


This seems to do the trick and the lag is now completly gone. Oh, and I'm already noticing how the memory is leaking...
 
Thread Closed share thread


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright ©2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 06:50 PM.


Powered by vBulletin
Copyright ©2000 - 2016, Jelsoft Enterprises Ltd.