OgreBipedLib.ms 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. include "ogre/lib/ogreSkeletonLib_usefulfns.ms"
  2. -----------------------------------------------------------------------------
  3. -- gets keyframes from the controllers animation
  4. -----------------------------------------------------------------------------
  5. function getTimeList obj firstframe lastframe samplerate IKsamplerate =
  6. (
  7. local list,rotContr,posContr,e ;
  8. list = #(firstframe) ;
  9. list2 = #() ; -- this is the list which will be returned.
  10. -- Biped Bones and the root: Bip01 for example don't have the same controller
  11. -- Root : Bip01
  12. if (isPelvis obj) then (
  13. -- vertical controller
  14. for e in obj.controller.vertical.controller.keys do (
  15. t =e.time ;
  16. if (t>firstFrame and t<=lastFrame) then (
  17. append list t ;
  18. --print t ;
  19. )
  20. )
  21. -- horizontal controller
  22. for e in obj.controller.horizontal.controller.keys do (
  23. t =e.time ;
  24. if (t>firstFrame and t<=lastFrame) then
  25. append list t ;
  26. )
  27. -- turn controller
  28. for e in obj.controller.turning.controller.keys do (
  29. t =e.time ;
  30. if (t>firstFrame and t<=lastFrame) then
  31. append list t ;
  32. )
  33. sort list ;
  34. )
  35. -- Biped Bones
  36. else if (isKindOf obj Biped_Object) then (
  37. for e in obj.controller.keys do (
  38. t =e.time ;
  39. if (t>firstFrame and t<=lastFrame) then
  40. append list t ;
  41. )
  42. )
  43. -- Standard Bones
  44. else
  45. (
  46. --print obj.name;
  47. --print (classof obj.controller) ;
  48. if (classof obj.controller == prs) then -- standard controller
  49. (
  50. rotContr = obj.rotation.controller ;
  51. posContr = obj.pos.controller ;
  52. for e in rotContr.keys do
  53. (
  54. t = e.time ;
  55. if (t>firstFrame and t<=lastFrame) then
  56. append list t ;
  57. )
  58. for e in posContr.keys do
  59. (
  60. t = e.time ;
  61. if (t>firstFrame and t<=lastFrame) then
  62. append list t ;
  63. )
  64. )
  65. else if ((classof obj.controller == IK_ControllerMatrix3Controller) or (classof obj.controller == IKControl)) then -- IK controller
  66. (
  67. local IKSR = IKsamplerate;
  68. if (IKSR == 0.0) then
  69. IKSR = 1.0;
  70. i=firstFrame as Float;
  71. while (i<=lastFrame) do
  72. (
  73. append list (i as Float);
  74. i = i + IKSR;
  75. )
  76. )
  77. )
  78. append list (firstFrame as Float); -- add a keyframe on the first frame
  79. append list (lastFrame as Float); -- add a keyframe on then last frame
  80. if (samplerate > 0) then -- sample the animation by adding keyframes on regular intervals
  81. (
  82. i=firstFrame as Float;
  83. while (i<=lastFrame) do
  84. (
  85. append list (i as Float);
  86. i = i + samplerate;
  87. )
  88. )
  89. sort list ;
  90. -- if several keyframes have the same value, we keep just one
  91. keepLoneValues list list2 ;
  92. list2 ;
  93. )
  94. -----------------------------------------------------------------------------
  95. -- write <track />
  96. -- Selected keys belongs to [firstframe,lastFrame]
  97. -- time = (key.time - firstFrame)*length/(lastFrame-firstFrame)
  98. -- (e.g. first key has time 0.)
  99. -----------------------------------------------------------------------------
  100. function writeTrack bone_name boneId firstframe lastframe samplerate IKsamplerate length scale flipYZ outFile=
  101. (
  102. local angle,timef,i,bname,d,mref,mparent ;
  103. -- displays information in the maxscript listener
  104. if (not g_MAX) then
  105. format "retrieving key information for % ...\n" (bone_name) ;
  106. -- gets bone acording to the parameter boneId
  107. bname = bone_name ;
  108. replaceSpaces bname ;
  109. d = getNodeByName bname ;
  110. -- gets keyframe list
  111. timelist = getTimeList d firstframe lastframe samplerate IKsamplerate;
  112. -- track header
  113. format("\t\t\t\t<track bone = \"%\">\n") bname to:outFile ;
  114. format("\t\t\t\t\t<keyframes>\n") to:outFile ;
  115. -- gets initial transform at frame 0f
  116. at time 0f (
  117. initTform = d.transform ;
  118. if (not isRootUniversal2 d) then (
  119. mparent = d.parent.transform ;
  120. initTform = initTform*inverse(mparent) ;
  121. )
  122. else if (flipYZ) then (
  123. if (not g_MAX) then
  124. format " - flipping root track..." ;
  125. -- we add the bip Transform
  126. --initTform = initTform * d.controller.rootNode.transform ;
  127. initTform = flipYZTransform initTform ;
  128. )
  129. )
  130. -- for each frame in the list
  131. for i in timelist do
  132. (
  133. -- moves slider time and compute OGRE time
  134. at time i (
  135. timef = ((float) (i-firstFrame)*length)/(lastframe - firstframe ) ;
  136. -- First, rotation which depends on initial transformation
  137. Tform = d.transform ;
  138. -- if this is the pelvis
  139. if (isRootUniversal2 d) then (
  140. mparent = matrix3 1 ;
  141. -- if flipYZ == true
  142. if (flipYZ) then
  143. Tform = flipYZTransform Tform ;
  144. )
  145. else
  146. mparent = d.parent.transform ;
  147. -- computes rotation
  148. mref = initTform*mparent ;
  149. Tform = Tform*inverse(mref) ;
  150. -- rotation part is saved.
  151. --rot = Tform.rotation as angleaxis ;
  152. --angle = - degToRad (rot.angle) ; -- don't know why there must be this minus :((((((
  153. rot = toAngleAxis Tform.rotation ;
  154. axis = rot.axis;
  155. angle = - rot.angle;
  156. -- Then, position which depends on parent
  157. Tform=d.transform ;
  158. Tform=Tform*inverse(mparent) ;
  159. -- if this is the root bone and flipYZ == true
  160. if (isRootUniversal2 d and flipYZ) then (
  161. Tform = flipYZTransform Tform ;
  162. )
  163. -- substracts position of the initial transform
  164. Tform.pos -= initTform.pos ;
  165. Tform.pos = Tform.pos * scale ;
  166. pos = Tform.pos ;
  167. -- writes them !
  168. if (abs(pos.x)<1e-5) then pos.x = 0 ;
  169. if (abs(pos.y)<1e-5) then pos.y = 0 ;
  170. if (abs(pos.z)<1e-5) then pos.z = 0 ;
  171. format("\t\t\t\t\t\t<keyframe time=\"%\">\n") timef to: outFile ;
  172. format("\t\t\t\t\t\t\t<translate x=\"%\" y=\"%\" z=\"%\" />\n") pos.x pos.y pos.z to: outFile ;
  173. format("\t\t\t\t\t\t\t<rotate angle=\"%\">\n") angle to:outFile ;
  174. format("\t\t\t\t\t\t\t\t<axis x=\"%\" y=\"%\" z=\"%\" />\n") (axis.x) (axis.y) (axis.z) to:outFile ;
  175. format("\t\t\t\t\t\t\t</rotate>\n") to:outFile ;
  176. format("\t\t\t\t\t\t</keyframe>\n") to:outFile ;
  177. )
  178. )
  179. -- track end
  180. format("\t\t\t\t\t</keyframes>\n") to:outFile ;
  181. format("\t\t\t\t</track>\n") to: outFile ;
  182. )
  183. -------------------------------------------------------------------------------------------------
  184. ------------------------------------------- WRITE SKELETON --------------------------------------
  185. -------------------------------------------------------------------------------------------------
  186. -------------------------------------
  187. -- List of bones in the hierarchy
  188. -------------------------------------
  189. global BonesList=#()
  190. global RootsList=#()
  191. -------------------------------------
  192. -- helper functions to build skeleton
  193. -------------------------------------
  194. -----------------------------------------------------------------
  195. -- recursive function to build the list of bones for the skeleton
  196. -----------------------------------------------------------------
  197. function computeBList b sk phy exportHelpers =
  198. (
  199. bname = b ;
  200. bone = getNodeByName bname ;
  201. if (findItem BonesList bname == 0) then
  202. if (isKindOf bone BoneGeometry or iskindOf bone Biped_Object or (exportHelpers and (isPartOfModifier bone sk phy)) ) then
  203. append BonesList bname ;
  204. childrenArray = bone.children ;
  205. for i=1 to childrenArray.count do
  206. (
  207. if (isKindOf bone BoneGeometry or iskindOf bone Biped_Object or (exportHelpers and (isPartOfModifier bone sk phy))) then
  208. computeBList (replaceSpaces childrenArray[i].name) sk phy exportHelpers;
  209. )
  210. )
  211. function addHelpersToHierarchy phy sk =
  212. (
  213. if (sk != undefined) then
  214. (
  215. for i=1 to (skinOps.GetNumberBones sk) do
  216. (
  217. bname = skinOps.GetBoneName sk i 1 ;
  218. replaceSpaces bname ;
  219. d = getNodeByName bname ;
  220. if (iskindof d helper) then
  221. append BonesList bname ;
  222. )
  223. )
  224. else if (phy != undefined) then
  225. (
  226. for i=1 to (physiqueOps.GetBoneCount $) do
  227. (
  228. bname = (physiqueOps.GetBones $)[i].name;
  229. replaceSpaces bname ;
  230. d = getNodeByName bname ;
  231. if (iskindof d helper) then
  232. append BonesList bname ;
  233. )
  234. )
  235. )
  236. -----------------------------------------------------------------
  237. -- find the root(s) of the rhierarchy
  238. -----------------------------------------------------------------
  239. function getHierarchyRoots phy sk exportHelpers =
  240. (
  241. local rootstab=#();
  242. if (sk != undefined) then
  243. (
  244. for i=1 to (skinOps.GetNumberBones sk) do
  245. (
  246. bname= skinOps.GetBoneName sk i 1 ;
  247. replaceSpaces bname ;
  248. d = getNodeByName bname ;
  249. while (d.parent!=undefined and (iskindof d.parent BoneGeometry or iskindOf d.parent Biped_Object or (exportHelpers and (isPartOfModifier d.parent sk phy)) )) do
  250. (
  251. d = d.parent
  252. )
  253. trouve = 0;
  254. --format("new potential root bone \"%\"\n") (replaceSpaces d.name) ;
  255. for j=1 to rootstab.count do
  256. (
  257. if (rootstab[j]!=undefined and (rootstab[j]==(replaceSpaces d.name)))then
  258. (
  259. trouve = 1;
  260. exit;
  261. )
  262. )
  263. if trouve==0 then
  264. (
  265. if (iskindof d BoneGeometry or iskindOf d Biped_Object or (exportHelpers and (isPartOfModifier d sk phy)) ) then
  266. (
  267. if (not g_MAX) then
  268. format("new root bone \"%\"\n") (replaceSpaces d.name) ;
  269. rootstab[rootstab.count+1] = (replaceSpaces d.name) ;
  270. )
  271. )
  272. )
  273. )
  274. else if (phy != undefined) then -- physique modifier
  275. (
  276. for i=1 to (physiqueOps.GetBoneCount $) do
  277. (
  278. bname = (physiqueOps.GetBones $)[i].name;
  279. replaceSpaces bname ;
  280. d = getNodeByName bname ;
  281. while (d.parent!=undefined and (iskindof d.parent BoneGeometry or iskindOf d.parent Biped_Object or (exportHelpers and (isPartOfModifier d.parent sk phy)) )) do
  282. (
  283. d = d.parent
  284. )
  285. trouve = 0;
  286. --format("new potential root bone \"%\"\n") (replaceSpaces d.name) ;
  287. for j=1 to rootstab.count do
  288. (
  289. if (rootstab[j]!=undefined and (rootstab[j]==(replaceSpaces d.name)))then
  290. (
  291. trouve = 1;
  292. exit;
  293. )
  294. )
  295. if trouve==0 then
  296. (
  297. if (iskindof d BoneGeometry or iskindOf d Biped_Object or (exportHelpers and (isPartOfModifier d sk phy))) then
  298. (
  299. if (not g_MAX) then
  300. format("new root bone \"%\"\n") (replaceSpaces d.name) ;
  301. rootstab[rootstab.count+1] = (replaceSpaces d.name) ;
  302. )
  303. )
  304. )
  305. )
  306. rootstab;
  307. )
  308. -----------------------------------------------------------------
  309. -- function to build the list of bones for the skeleton
  310. -----------------------------------------------------------------
  311. function computeBonesList phy sk exportHelpers =
  312. (
  313. RootsList = getHierarchyRoots phy sk exportHelpers; -- find the roots of the current hierarchy
  314. print RootsList;
  315. for b in RootsList do
  316. (
  317. computeBList b sk phy exportHelpers;
  318. )
  319. -- add the nodes that are parts of the skin (or physique) modifier but are neither biped_object nor standard bones
  320. -- only helpers (Point, Dummy) at the moment...
  321. -- addHelpersToHierarchy phy sk ;
  322. )
  323. ------------------
  324. -- write <bones />
  325. ------------------
  326. function writeB bone_name id scale flipYZ outFile =
  327. (
  328. -- gets bone acording to the parameter boneId
  329. bname = bone_name ;
  330. replaceSpaces bname;
  331. d = getNodeByName bname ;
  332. -- gets initial transform at frame 0f
  333. format("\t\t<bone id=\"%\" name=\"%\">\n") (id-1) bname to:outFile ;
  334. slidertime = 0f ;
  335. Tform = d.transform ;
  336. if (not isRootUniversal2 d) then (
  337. mparent = d.parent.transform ;
  338. Tform = Tform*inverse(mparent) ;
  339. )
  340. Tform.pos = Tform.pos * scale ;
  341. if ((isRootUniversal2 d) and flipYZ) then (
  342. if (not g_MAX) then
  343. format "- Flipping root... \n" ;
  344. Tform = flipYZTransform Tform ;
  345. )
  346. pos = Tform.pos ;
  347. --rot = Tform.rotation as angleaxis ;
  348. --angle = - degToRad (rot.angle) ; -- don't know why there must be this minus :((((((
  349. rot = toAngleAxis Tform.rotation ;
  350. angle = - rot.angle ;
  351. -- if (abs(pos.x)<1e-5) then pos.x = 0 ;
  352. -- if (abs(pos.y)<1e-5) then pos.y = 0 ;
  353. -- if (abs(pos.z)<1e-5) then pos.z = 0 ;
  354. -- Only object.transform was taken into account, but when mirror is applied
  355. -- object.scale is modified and become [-1,-1,-1] that's why we do what follows:
  356. if ((d.parent != undefined) and (hasproperty d.parent "scale")) then (
  357. pos = pos * d.parent.scale ;
  358. )
  359. format("\t\t\t<position x=\"%\" y=\"%\" z=\"%\" />\n") pos.x pos.y pos.z to:outFile ;
  360. format("\t\t\t<rotation angle=\"%\">\n") angle to:outFile ;
  361. format("\t\t\t\t<axis x=\"%\" y=\"%\" z=\"%\" />\n") rot.axis.x rot.axis.y rot.axis.z to:outFile ;
  362. format("\t\t\t</rotation>\n") to:outFile ;
  363. format("\t\t</bone>\n") to:outFile ;
  364. )
  365. -----------------------------
  366. -- write Bones (using writeB)
  367. -----------------------------
  368. function writeBones phy sk scale flipYZ exportHelpers outFile =
  369. (
  370. local i ;
  371. OgreExportObject.exportProgress.value = 0;
  372. if (BonesList.count == 0) then
  373. computeBonesList phy sk exportHelpers;
  374. format("\t<bones>\n") to:outFile;
  375. i = 0 ;
  376. for i=1 to BonesList.count do
  377. (
  378. OgreExportObject.exportProgress.value = (100.0*i/BonesList.count);
  379. writeB BonesList[i] i scale flipYZ outFile ;
  380. )
  381. format("\t</bones>\n") to:outFile;
  382. OgreExportObject.exportProgress.value = 100;
  383. )
  384. --------------------------
  385. -- write <bonehierarchy />
  386. --------------------------
  387. function writeH b outFile =
  388. (
  389. if (not isRootUniversal2 b) then
  390. (
  391. p = b.parent ;
  392. format("\t\t<boneparent bone=\"%\" parent=\"%\" />\n") (replaceSpaces b.name) (replaceSpaces p.name) to:outFile ;
  393. )
  394. )
  395. function writeHierarchy outFile =
  396. (
  397. OgreExportObject.exportProgress.value = 0;
  398. local bname,pelvis
  399. format("\t<bonehierarchy>\n") to:outFile ;
  400. for i=1 to BonesList.count do
  401. (
  402. OgreExportObject.exportProgress.value = (100.0*i/BonesList.count);
  403. b = getNodeByName BonesList[i] ;
  404. writeH b outFile ;
  405. )
  406. format("\t</bonehierarchy>\n") to:outFile ;
  407. OgreExportObject.exportProgress.value = 100;
  408. )
  409. -----------------------
  410. -- write <animations />
  411. -----------------------
  412. function writeAnim Anims samplerate IKsamplerate scale flipYZ outFile =
  413. (
  414. local i,n ;
  415. OgreExportObject.exportProgress.value = 0;
  416. format("\t<animations>\n") to: outFile ;
  417. for anm=1 to Anims.names.count do
  418. (
  419. format("\t\t<animation name=\"%\" length=\"%\">\n") Anims.names[anm] Anims.lengths[anm] to:outFile ;
  420. format("\t\t\t<tracks>\n") to:outFile
  421. n = BonesList.count ;
  422. for i = 1 to n do
  423. (
  424. OgreExportObject.exportProgress.value = (100.0*i/BonesList.count)/Anims.names.count;
  425. writeTrack BonesList[i] i Anims.startframes[anm] Anims.endframes[anm] samplerate IKsamplerate Anims.lengths[anm] scale flipYZ outFile ;
  426. )
  427. format("\t\t\t</tracks>\n") to:outFile
  428. format("\t\t</animation>\n") to: outFile ;
  429. )
  430. format("\t</animations>\n") to: outFile ;
  431. OgreExportObject.exportProgress.value = 100;
  432. )
  433. -------------------------------------------------------------
  434. -- write <skeleton /> main function
  435. -- write the animation in the file out_name + ".skeleton.xml"
  436. -- between the frame firstFrame and lastFrame
  437. -- and scale time according to length
  438. -------------------------------------------------------------
  439. function writeSkeleton pmesh exportOptions Anims out_name =
  440. (
  441. local sk,n,keys,initialKeys,messages,phy ;
  442. sk = getSkin pmesh ;
  443. phy = getPhysique pmesh ;
  444. if (sk == undefined and phy == undefined) then
  445. (
  446. MessageBox "There is no skin or physique modifier for this object" ;
  447. return false;
  448. )
  449. else
  450. (
  451. -- in order to perform, skin should be opened
  452. max modify mode ;
  453. if (sk != undefined) then
  454. modPanel.setCurrentObject pmesh.modifiers[#Skin] ;
  455. else -- physique
  456. modPanel.setCurrentObject pmesh.modifiers[#Physique] ;
  457. if (not g_MAX) then
  458. (
  459. format "------------------------------------------\n"
  460. format "------ OGRE skeleton Exporter Log ------\n"
  461. format "------------------------------------------\n"
  462. format "Exporter options :\n"
  463. for i=1 to Anims.names.count do
  464. format "Anim % - firstFrame: % - lastFrame: %\n" Anims.names[i] Anims.startframes[i] Anims.endframes[i] ;
  465. -- creates the output file
  466. outFile = createfile (out_name + ".skeleton.xml") ;
  467. )
  468. else
  469. (
  470. if (g_MAX_use_listener) then
  471. format("<ogrestartfile>%</ogrestartfile><ogrestartdata>\n") (outName + ".skeleton.xml");
  472. outFile = listener;
  473. )
  474. -- writes header
  475. format("<skeleton>\n") to:outFile ;
  476. if (not g_MAX) then
  477. format "Writing bones :\n" ;
  478. writeBones phy sk exportOptions.scale exportOptions.flipYZ exportOptions.exportHelpers outFile ;
  479. if (not g_MAX) then
  480. format "Writing bone hierarchy.\n" ;
  481. writeHierarchy outFile ;
  482. if (not g_MAX) then
  483. format "Writing bone tracks.\n" ;
  484. writeAnim Anims exportOptions.sampleRate exportOptions.ikSampleRate exportOptions.scale exportOptions.flipYZ outFile ;
  485. -- ecriture, fin des balises
  486. format("</skeleton>\n") to: outFile ;
  487. if (not g_MAX) then
  488. (
  489. format "------------------------------------------\n"
  490. format "---------- END ---------\n"
  491. format "------------------------------------------\n"
  492. close outFile ;
  493. )
  494. else
  495. (
  496. if (g_MAX_use_listener) then
  497. format("</ogrestartdata>\n") to: outFile;
  498. )
  499. messageBox "Exporting skeleton successful !"
  500. return true;
  501. )
  502. )