Sep 12 2013

Rigging Demos

Some one had asked for samples of animation setups i have done through out my career..
i lost allot of my work a few years back when my external drive died.. but recently i found this videos, which are a bit dated, but still hold a special place in my hart 🙂
anyway, if you are bored and looking for something to bore you even more check them out 🙂
httpv://youtu.be/FO3JVHBdwI8
httpv://youtu.be/6fQINze9c0I
httpv://youtu.be/307PdswKUJs


Jan 14 2013

Creating Menu’s in max

so very often TD’s look for ways to distribute their tools via menu’s. yet it has been my experience that using the code that’s documented can be really flaky seance any error half way through your code.. can make max go into to a weird state along with making your menu file corrupt all together (which means max my not start again for you until you fix this file). so while doing some work with manu’s i decided to put together a simple object oriented API that anyone could use to build this menu’s virtually with a limited number of commands..
the concept behind it is the new menu becomes a virtual object created by TD that he can append other items too.. once he is done appending this items he can commit his new menu to the ui, via the myMenu.commitMenu command.. pretty simple (i hope :D)

/*
example starts here
*/
filein @"C:\maxScript\libs\maxMenuBarApi.ms"
myMenu = ::maxMenuBarApi()



--make menu items
/*
makeMenuItem takes the following inputs
1)name to be used for the menu item..
2)category of the macro script it will be execute
3)varible name of the macros script to execute
*/

helloWorldMenuItem = myMenu.makeMenuItem "hello World Test" "0 Pixomondo Macros" "helloWorld"
helloPeterMenuItem =myMenu.makeMenuItem "hello Peter Test" "0 Pixomondo Macros" "helloPeter"
separatorMenuItem = myMenu.makeSeparator ()

menuI = #() --this will hold all the items we are adding to our menu..

append menuI helloWorldMenuItem
append menuI helloPeterMenuItem
append menuI separatorMenuItem

--adding sub menu to our menu
subMenu = myMenu.makeSubMenu "subMenu"
myMenu.addItem helloWorldMenuItem subMenu:subMenu
myMenu.addItem helloPeterMenuItem subMenu:subMenu
append menuI subMenu

--adding a nested sub menu
subMenu = myMenu.makeSubMenu "Nested sub menu"

menuA =  myMenu.makeSubMenu "menu A"
myMenu.addItem menuA subMenu:subMenu

menuB =  myMenu.makeSubMenu "menu B"
myMenu.addItem menuB subMenu:subMenu

myMenu.addItem helloWorldMenuItem subMenu:menuA
myMenu.addItem helloPeterMenuItem subMenu:menuA

myMenu.addItem helloWorldMenuItem subMenu:menuB
myMenu.addItem helloPeterMenuItem subMenu:menuB

append menuI subMenu

--let's add all the items to our ui now..
for m in menuI do myMenu.addItem m
--let's rename the menu
myMenu.setMenuName "My Menu Api Test"
--let's commit the menu
myMenu.commitMenu()

anyway the hope for this api is that TD’s can deploy menu’s faster, and with less code.. along with adding a separation of the building of the code, and the actual drawing of the menu’s.. in hope’s that bugs regarding the building of the data, will not corrupt any of the menu files of or put max in “strange limbo mode”

here’s what the API looks like..

/*
Max menu bar api
by Carlos Anguiano
*/
struct maxMenuBarApi 
(
	menuData, 
	fn dicGetKeys dic =
	(
		
        --spit the posible keys out  
        DNArray = dotNetObject "System.string[]" dic.keys.count  
        dic.keys.copyTo DNArray 0  
        out = for i = 1 to dic.keys.count collect (DNArray.get (i-1))  
		out
	),
	fn dicRemoveKey dic pkey =
	(
		if dic.item[pKey] != undefined then dic.remove pKey
	),
	fn dicSetProperty dic pKey pVal =
	(
		dicRemoveKey dic pKey
		dic.add pKey pVal
		pVal
	),
	fn getMenuName =
	(
		menuData.item["name"]
	),
	fn setMenuName newName =
	(
		dicSetProperty menuData "name" newName
	),
	fn getMenuItems subMenu:undefined =
	(
		if subMenu == undefined then subMenu = menuData
		subMenu.item["items"]
	),
	fn makeMenuItem itemName macroCat macroName  =
	(
		itemData = dotNetObject "System.Collections.Hashtable" 
		dicSetProperty itemData "type" "menuitem"
		dicSetProperty itemData "title" itemName
		dicSetProperty itemData "category" macroCat
		dicSetProperty itemData "macroName" macroName
		itemData
	),
	fn makeSubMenu itemName =
	(
		itemData = dotNetObject "System.Collections.Hashtable" 
		dicSetProperty itemData "type" "submenu"
		dicSetProperty itemData "title" itemName
		dicSetProperty itemData "items" #()

		itemData
	),
	fn makeSeparator =
	(
		itemData = dotNetObject "System.Collections.Hashtable" 
		dicSetProperty itemData "type" "separator"
		itemData
	),
	fn addItem item subMenu:undefined =
	(
		if subMenu == undefined then subMenu = menuData
		ar = getmenuItems subMenu:subMenu
		append ar item
		dicSetProperty subMenu "items" ar
		true
	),
	fn clearMenu =
	(
		mainMenu = menuMan.findMenu (getMenuName()) --see if the current menu already exists
		if mainMenu != undefined do -- if pixo menu exists then clean it out..
		(
			menuMan.unRegisterMenu mainMenu
			menuMan.updateMenuBar() 
			thePixoMenu = undefined
		)
		true
	),
	fn addItemToMenu def menu =
	(
		case def.item["type"] of
		(
			"menuitem":
			(
				theAction = menuMan.createActionItem def.item["macroName"] def.item["category"]
				theAction.setTitle def.item["title"]
				theAction.setUseCustomTitle true
				menu.addItem theAction -1
			)
			"separator": 
			(
				theAction = menuMan.createSeparatorItem()
				menu.addItem theAction -1
			)
			"submenu":
			(
				sb = menuMan.createMenu def.item["title"]
				theSubMenu = menuMan.createSubMenuItem def.item["title"] sb
				menu.addItem theSubMenu -1
				for i in def.item["items"] do addItemToMenu i sb
			)
			default:(format "% is not a valid menu item..\n" def.item["type"])
		)	
	),
	fn commitMenu =
	(
		mainMenuBar = menuMan.getMainMenuBar() 
		menuItems = getMenuItems()
		
		if menuItems == 0 then 	throw "There are no items in this menu to commit"
		
		clearMenu()
		
		newMenu = menuMan.createMenu  (getMenuName())
		for it in menuItems do addItemToMenu it newMenu		
		
		SubMenu = menuMan.createSubMenuItem  (getMenuName()) newMenu
		
		mainMenuBar.addItem SubMenu -1
		menuMan.updateMenuBar() 
	),
	fn _init_ = 
	(
		menuData = dotNetObject "System.Collections.Hashtable" 
		dicSetProperty menuData "name" "testMenu"
		dicSetProperty menuData "items" #()

		true
	),
	init = _init_()
)



Jan 10 2012

Singular Value Decomposition (SVD) and object oriented Bounding Boxes

So a continuation of my previous post.. while trying to figure out how to implement SVD (Singular Value Decomposition) algorithm to figure out the best possible aligned bounding box for a set of points.
my friend Ghram Fyffe pointed my to a python library called “numpy” which has great SVD functions that is incredibly easy to use 🙂
seance 3ds max does not support python, i decided i would write the python code to read all the vertex information from a text file, and then overwrite the content of that text file with the resulting alignment matrix.
this method should be eazy to implement into any amp even if it does not have native python support.

i hope this code is helpful to you some one. here it is!

'''
PCA optimized axis generator generator (now threaded)

By Carlos Anguiano
this script will process a text file with point data
and generate and optimized object orient bounding box for the point set
c:\python26_64\python.exe
"C:\svnTools\trunk\S2\exchange\software\managed\pythonScripts\PCAOptOOBB\PCAOptOBB.py"
"C:\Users\SCANLI~2\AppData\Local\Temp\PointCloudData
'''
import time
import threading
import sys
import string
import numpy

import os
#this argument feed the script the folder which to parse for pointCloud data files
#PCFld = sys.argv[1]
PCFld = 'C:\Users\SCANLI~2\AppData\Local\Temp\PointCloudData'
maxThreads=8

def OptmizedTransformAxisFromPointCloadFile (infile):
     lines = open(infile,'r').readlines()
     lCount = len(lines)
     lCount
     vAr = ""
     for i in range(lCount):
         l = lines[i]
         vector = (l.rstrip())
         vAr += vector

         if i != (lCount-1):
             vAr += ";"
     #once you turn the file content into a string list (look up charArrays) the magic happens
     m = numpy.matrix(vAr)
     USV = numpy.linalg.svd(m)
     return USV[2]

def formatData(data):
     lines = []
     for i in range(3):
         A = numpy.asarray(data[i])
         x = A[0][0]
         y = A[0][1]
         z = A[0][2]
         s = "["+str(x)+","+str(y)+","+str(z)+"]\n"
         lines.append(s)
     return lines

class OptTransAxisFromPCF (threading.Thread):
     def __init__(self,filename):
         self.filename = filename
         threading.Thread.__init__(self)

     def run(self):
         filename = self.filename
         axisData = OptmizedTransformAxisFromPointCloadFile(filename)
         lines = formatData(axisData)
         f = open(filename,'w')
         f.writelines(lines)

def OptmizedTAxFromPCldFiles (Fldr):
     pcFiles = os.listdir(Fldr)
     if len(pcFiles) == 0:
         print "no files to process in this folder"
         return false

     for f in pcFiles:
         while(threading.activeCount()>=(maxThreads + 1)):
             print 'Waiting for a thread to free up...'
             time.sleep(.25)
         absF = Fldr+"\\"+f
         OptTransAxisFromPCF(absF).start()
     while(threading.activeCount() != 1):
         time.sleep(.25)

Optmiz1edTAxFromPCldFiles(PCFld)