Notifications
Clear all

[Closed] From script to plugin – Speed

I know its a really wide open question with lots of variables…no pun intended…and dependent on what is being done, but generally what are the speed increases when creating a plugin from a script?

12 Replies

totally unscientific I would say function calls are very slow (comparatively to c++) in mxs, both to other mxs functions and calls to compiled mxs exposed dlx functions.

saying that I don’t think speed is always the reason to go down the plugin route, there are other considerations to take into account. Even though supporting a multitude of different versions and autodesk moving the goalposts every year A plugin is easier to manage as the complexity increases. It’s usually a single entity (not always the case but mostly) which goes into one folder, you can even store multiple object/mods/utilities into a single plugin. Also it’s a much nicer debugging environment in visual studio which also helps when complexity increases.

Another consideration is ui programming is much less work in mxs than in the sdk and much quicker to get something up and running and usuable.

 lo1

As you already know, from 0% to 100000%. You at least need to clue us in on what the script does.

Generally it would involve raycasting i guess. Basically, taking a camera viewport and shooting rays out into the scene, through each pixel, and returning a cooresponding 3d coordinate. The script that i am using right now is slow, and we need to be able to use viewport/image sizes up to high end DSLR dimensions. I can post the code that i’m using… since its a sample that i found.

Here is the script (original author…Chris Shuman aka HybridArtist at maxforums) that i’m using…with a couple things added/removed.


 start = timeStamp()
 vp = viewport.activeViewport
 if viewport.IsPerspView() then
 (
 
 HitLocations = #() -- create array to hold hit locations
 viewportSize = getViewSize() -- get the currently selected viewport size
 print viewportSize  --prints out the captured viewport dimensions
 widthDiv = (1.0 / viewportsize[1]) * 2.0;
 	
 heightDiv = (1.0 / viewportsize[2]) * 2.0;
 	
 w2sMat = viewport.getTM();
 s2wMat = Inverse(w2sMat);--calc the screen-2-world matrix
 viewDir = -s2wMat.row3;
 viewOrigin = s2wMat.row4;
 s2wMat.row4 = [0,0,0];--remove any translation
 --print (ray viewOrigin viewDir);
 centerPos = viewOrigin * viewport.getTM();--project the viewpoint origin on screen
 rayDir = [0,0,0];
 
 for y = 1 to viewportsize[2] do -- foreach image row
 (
 for x = 1 to viewportsize[1] do -- foreach image column
 (
 for g in geometry do --foreach geometry object
 (
 local normX = (x * widthDiv) - 1.0;
 local normY = -((y * heightDiv) - 1.0);--invert the ycoord since y=0 represents upper edge
 local normPos = [normX,normY,-1.0];
 
 rayDir = normalize (normPos * s2wMat);
 tempRay = ray viewOrigin rayDir;
 
 IntRay = intersectray g tempRay;
 if intRay != undefined then
 (
 --print g;
 append HitLocations IntRay.pos; -- if hit add 3d position to "HitLocations Array"
 )
 )
 )
 )
 print HitLocations -- print hit locations to lisiner
 )
 else
 print "ERROR: no perspective viewport"
 end = timeStamp()
 format "Processing took % seconds
" ((end - start) / 1000.0)
 

Be mindful that it will take a long time to process unless the current viewport is really small.
As i mentioned…the result needs to be way, way faster. Not sure if optimizing the script will do it or whether or not it needs to be a plugin.

if you merge the clones of scene geometry into a single mesh you can do something like this…

 start = timeStamp()
   vp = viewport.activeViewport
   if viewport.IsPerspView() then
   (
   
  	 HitLocations = #() -- create array to hold hit locations
  	 viewportSize = getViewSize() -- get the currently selected viewport size
  	 print viewportSize  --prints out the captured viewport dimensions
  	 widthDiv = (2.0 / (viewportsize[1] - 1));
  	 heightDiv = (2.0 / (viewportsize[2] - 1));
  	 w2sMat = viewport.getTM();
  	 s2wMat = Inverse(w2sMat);--calc the screen-2-world matrix
  	 viewDir = -s2wMat.row3;
  	 viewOrigin = s2wMat.row4;
  	 s2wMat.row4 = [0,0,0];--remove any translation
  	 centerPos = viewOrigin * viewport.getTM();--project the viewpoint origin on screen
  	 rayDir = [0,0,0];
  	 
  	 aspect = viewportSize.x/viewportSize.y;
  	 
  	 cGrid = RayMeshGridIntersect();
  	 cGrid.initialize 25;
  	 cGrid.addNode	$scene_geometry
  	 cGrid.buildGrid();
  	 
  	 for y = -1 to viewportsize[2] do -- foreach image row
  	 (
  		 for x = -1 to viewportsize[1] do -- foreach image column
  		 (
  			local normX = (x * widthDiv) - 1.0;
  			local normY = -((y * heightDiv) - 1.0);--invert the ycoord since y=0 represents upper edge
  			local normPos = [normX,normY/aspect,-aspect * 2];
  			raydir = normalize (normPos * s2wMat);
  			 
  			index = cGrid.intersectRay viewOrigin raydir false;
  			if index > 0 then
  			( 
  				chit = cGrid.getClosestHit()
  				pos =  viewOrigin + (rayDir * (cGrid.getHitDist chit))
  				append HitLocations pos; -- if hit add 3d position to "HitLocations Array"
  			)
  		 )
  	 )
  	 cGrid.free();
  	 
  	 fstream = openFile "c:\hitlocations.dat" mode:"wt";
  	 if fstream != undefined then
  	 (
  		for i in HitLocations do
  		(
  			format "%
" i to:fstream;
  		)
  		flush	fstream;
  		close fstream;
  	)	
   )
   else
   print "ERROR: no perspective viewport"
   end = timeStamp()
   format "Processing took % seconds
" ((end - start) / 1000.0)

also i fine tuned your method so you get a better resolution. takes about 30 secs on a 613 x 395 viewport and about 25% of that is saving the file.

How about doing a temp render and reading the resulting bitmap back in?

hkrol

We originally tried it that way. Basically rendering a colour image and a cooresponding depth map. Our initial thought was that we could take the pixel colour from the render and the grayscale value from the depth map…which we could associate the min/max distance. This kind of worked as you can see from my example above…but it wasn’t accurate…or fast. The speed of acquiring the 3d points is the big issue. We would have anywhere between 200-1000 images to capture and recolour the 3d coordinate data from…even if its automated…the calculation times might become an issue.

I think a GLSL shader should be able to do this quite quickly. If you look at the last example on the page below, the shader is returning a value based on the normal direction of the surface. It shouldn’t be too difficult to get it to return a colour based on position of the surface at that point.
http://www.spot3d.com/vray/help/200R1/examples_vrayglsl.htm

I’m not really the best coder here, but I got your script down from 594 seconds to 16 seconds with 2 objects that fill the screen at 613×395.

Basically I tried to use less variables in the loop. And print to memory instead of the listener.

At first I didn’t realize you were trying to save the hit locations, and it only takes about 6 seconds for the actual intersectRay fucntion. So the rest is saving the file. There must be a faster way to do that.


(
	start = timeStamp()
	s = "" as stringStream
	vp = viewport.activeViewport

	if viewport.IsPerspView() then
	 (
		 viewportSize = getViewSize() -- get the currently selected viewport size
		 widthDiv = (1.0 / viewportsize[1]) * 2.0;
		 heightDiv = (1.0 / viewportsize[2]) * 2.0;
			
		 w2sMat = viewport.getTM();
		 s2wMat = Inverse(w2sMat);--calc the screen-2-world matrix
		 viewDir = -s2wMat.row3;
		 viewOrigin = s2wMat.row4;
		 s2wMat.row4 = [0,0,0];--remove any translation
		 
		 for y = 1 to viewportsize[2] do -- foreach image row
		 (
			 for x = 1 to viewportsize[1] do -- foreach image column
			 (
				 rayDir = (ray viewOrigin (normalize (([(x * widthDiv) - 1.0,-((y * heightDiv) - 1.0),-1.0]) * s2wMat)))
				 
				 for g in geometry do --foreach geometry object
				 (
					 IntRay = intersectray g rayDir;
					 if intRay != undefined then
					 (
						 format "%
" IntRay.pos to:s
					 )
				 )
			 )
		 )

		fName = "$temp\SaveHitLocations.txt"
		cf = createFile fName
		format "%" (s as string) to:cf
		close cf
		edit fName
	 )
	 else
	 (
		print "ERROR: no perspective viewport"
	 )
	 
	end = timeStamp()
	format "Processing took % seconds
" ((end - start) / 1000.0)
)

Page 1 / 2