[Closed] Get object Positions from dotNet
This is a bit of a long term problem for me. Basically I am wanting to do a whole bunch of math in C#, but the bottleneck in my case is getting Object positions accessable from my C# Classes …
for example. $Box1 has 5000 frames worth of animation, What is the fastest way you can thing of to get it’s position at each frame accessable from a C# class?
In my C# Class i have defined a property which is a list of Point3Ds which I with then further process.
ObjectPos = new List<Point3D>();
so in MaxScript I’m running a loop to write the positions to the above list, but it is slow. (average 250ms per object)
p3DClass = dotnetclass "System.Windows.Media.Media3D.Point3D"
for n = 0 to 5000 do -- this is the slow bit
(
-- axs.DBdat is an instance of the C# class with all the fancy math in it...
o = at time n $Box001.pos
axs.DBdat.ObjectPos.Add (dotNetObject p3DClass o.X o.Y o.Z)
)
-- works through the list and does stuff... runs great
axs.DBdat.processMotion ()
Any thoughts on Optimizing this sort of thing?
Would there be anything workable using the MaxSharp DLL maybe? Interrogate the scene directly from dotNet?
Cheers
Mikie
My guess is that using a for-collect loop to build a maxscript array first, and then converting that into a .NET array implicitly by passing it to a .NET function may be faster.
Something like
p3DClass = dotnetclass "System.Windows.Media.Media3D.Point3D"
pts = for n = 0 to 5000 collect ((o = at time n $Box0001.pos); dotNetObject p3DClass o.X o.Y o.Z)
axs.DBdat.processMotion pts
Nice. Another thing that might improve performance is replacing the Point3D by a float or double array. Then if you really need the Point3D class in your processMotion implementation you can perform the conversion in there.
You’d have to benchmark whether creating a small array is indeed faster than creating a new .NET object in maxscript, but it might just be.
I think this will definitely be faster, though double might be redundant, if I remember correctly 3dsmax saves coordinates as floats.
Ah yeah if max uses single precision floats then definitely use a float array. Use the minimal size data type possible without losing precision.
Thanks Guys… Float Array is indeed the fastest.
(Until I can figure out how to run this asynchronously from dotNet)
Well, I’ve found my bottleneck, and some of my objects, which rely heavily on script controllers to determine their position, can only get through a 5k frame timeline in something like 2.9 seconds. (Other objects complete, in 750ms, some in 80ms)
Before I can check for certain motion errors, I need to collect float arrays for up to 24 objects worth of data. So I thought I’d have a crack at using Synchnonizedbackground workers.
something like the following with 3 backgroundThreads looking at different objects :
backgroundThread1 = dotnetobject "CSharpUtilities.SynchronizingBackgroundWorker"
backgroundThread1.WorkerSupportsCancellation = true
backgroundThread1.WorkerReportsProgress = true
fn threadwork1 =
(
ts1 = timestamp()
for n = 0f to 4210f do
(
--set time n -- NB: set time makes the background worker shit the bed
pt = at time n STK.groupList[2].groupObj.pos -- reference to an object with position script controller
STK.axisList[1].Dbdat.positions.Add pt.X -- Dbdat is a c# class
STK.axisList[1].Dbdat.positions.Add pt.y -- positions is a List<float> property
STK.axisList[1].Dbdat.positions.Add pt.z
)
ts2 = timestamp()
format "thread1 took: %
" (ts2-ts1)
)
dotNet.addEventHandler backgroundThread1 "DoWork" threadwork1
-- dotNet.setLifetimeControl backgroundThread1 #dotnet --had a play
backgroundThread1.RunWorkerAsync()
I end up with the max number of simultanious errors displayed error which is caused by the below:
’ Unknown error occoured while Max was performing Garbage Collection…’
If i try to run a second or thrird thread, looking at the other objects in this hierarchy max crashes rather hard. Interstingly I get different errors when checking objects with slightly more complex script controllers on them (tension solving recursive function)
– Runtime error: dotNet runtime exception: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. <<
The code for the position script controller is pasted below, so you get an idea of the kind of calcs involved… any thoughts?
resX = resY = ResZ = 0.0
D = (distance p1.pos p2.pos)
r0 = (distance p1.pos h1.pos) -- p.s. h1 and h2 object positions are based on a rather nasty rotation controller on yet another object
r1 = (distance p2.pos h2.pos)
-- finds circle - circle intersect between circles at p1 and p2, with radii r1 and r1
-- returns lower of two points
if D > (r0 + r1) or D < abs(r0 - r1) or (D == 0 and r0 == r1) then
(
-- there are no solutions
resX = resY = ResZ = 0.0
)
else
(
K = 0.25 * sqrt(((r0 + r1)^2 - D^2) * (D^2 - (r0 - r1)^2))
pt1X = 0.5 *(p2.pos.X + p1.pos.X) + 0.5*(p2.pos.X - p1.pos.X)*(r0^2 - r1^2)/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2) + (2.0*(p2.pos.Z - p1.Pos.Z)*K/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2))
pt1Z = 0.5 *(p2.pos.Z + p1.pos.Z) + 0.5*(p2.pos.Z - p1.pos.Z)*(r0^2 - r1^2)/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2) + (-2.0*(p2.pos.X - p1.Pos.X)*K/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2))
pt2X = 0.5 *(p2.pos.X + p1.pos.X) + 0.5*(p2.pos.X - p1.pos.X)*(r0^2 - r1^2)/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2) + (2.0*(p2.pos.Z - p1.Pos.Z)*K/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2))
pt2Z = 0.5 *(p2.pos.Z + p1.pos.Z) + 0.5*(p2.pos.Z - p1.pos.Z)*(r0^2 - r1^2)/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2) + (-2.0*(p2.pos.X - p1.Pos.X)*K/((p2.pos.X - p1.pos.X)^2 + (p2.pos.Z - p1.pos.Z)^2))
if pt1Z <= pt2Z then
(
resX = pt1X; resZ = pt1Z;
)
else
(
resX = pt2X; resZ = pt2Z;
)
)
resY = p1.pos.Y + ((p2.pos.Y - p1.pos.Y)*((distance [resX,0] [p1.pos.X,0])/(distance [p1.pos.X,0] [p2.pos.X,0])))
[ resX,resY,resZ ]