ThreeJSAnimationExporter.ms 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733
  1. rollout ThreeJSExporter "ThreeJSExporter"
  2. (
  3. -- Variables
  4. local ostream,
  5. threeMatrix = (matrix3 [1,0,0] [0,0,1] [0,-1,0] [0,0,0]),
  6. headerFormat = "\"metadata\":
  7. {
  8. \"sourceFile\": \"%\",
  9. \"generatedBy\": \"3ds max ThreeJSExporter\",
  10. \"formatVersion\": 3,
  11. \"vertices\": %,
  12. \"normals\": %,
  13. \"colors\": %,
  14. \"uvs\": %,
  15. \"triangles\": %,
  16. \"materials\": %
  17. },
  18. ",
  19. vertexFormat = "%,%,%",
  20. vertexNormalFormat = "%,%,%",
  21. UVFormat = "%,%",
  22. triFormat = "%,%,%,%",
  23. triUVFormat = "%,%,%,%,%,%,%",
  24. triNFormat = "%,%,%,%,%,%,%",
  25. triUVNFormat = "%,%,%,%,%,%,%,%,%,%",
  26. footerFormat = "\n}",
  27. boneFormat = "\t\t{
  28. \t\t\t\"parent\" : %,
  29. \t\t\t\"name\" : \"%\",
  30. \t\t\t\"pos\" : %,
  31. \t\t\t\"scl\" : %,
  32. \t\t\t\"rotq\" : [%,%,%,%]
  33. \t\t}",
  34. animHeaderFormat = "\t\"animation\" : {
  35. \t\t\"name\" : \"Action\",
  36. \t\t\"fps\" : %,
  37. \t\t\"length\" : %,
  38. \t\t\"hierarchy\" : [\n",
  39. animBoneHeaderFormat = "\t\t\t{
  40. \t\t\t\t\"parent\" : %,
  41. \t\t\t\t\"keys\" : [\n",
  42. keyFormat = "\t\t\t\t\t{
  43. \t\t\t\t\t\t\"time\":%,
  44. \t\t\t\t\t\t\"pos\" :[%,%,%],
  45. \t\t\t\t\t\t\"rot\" :[%,%,%,%],
  46. \t\t\t\t\t\t\"scl\" :%
  47. \t\t\t\t\t}",
  48. animBoneFooterFormat = "\t\t\t\t]
  49. \t\t\t}",
  50. animFooterFormat = "\n\n\t\t]
  51. \t}\n"
  52. -------------------------------------------------------------------------------------
  53. -- User interface
  54. group "ThreeJSExporter v0.8"
  55. (
  56. label msg "Exports selected meshes in Three.js ascii JSON format" align:#left
  57. hyperLink lab1 "Original source at GitHub" address:"https://github.com/alteredq/three.js/blob/master/utils/exporters/max/ThreeJSExporter.ms" color:(color 255 120 0) align:#left
  58. label dummy1 "--------------------------------------------------------" align:#left
  59. checkbox exportColor "Export vertex colors" checked:false enabled:true
  60. checkbox exportUv "Export uvs" checked:true enabled:true
  61. checkbox exportNormal "Export normals" checked:true enabled:true
  62. checkbox smoothNormal "Use vertex normals" checked:false enabled:true
  63. label dummy2 "--------------------------------------------------------" align:#left
  64. checkbox flipYZ "Flip YZ" checked:false enabled:false
  65. checkbox flipUV "Flip UV" checked:false enabled:false
  66. checkbox flipFace "Flip all faces" checked:false enabled:false
  67. checkbox autoflipFace "Try fixing flipped faces" checked:false enabled:false
  68. label dummy3 "--------------------------------------------------------" align:#left
  69. spinner fps "Animation speed (FPS)" range:[0,1000,25] type:#integer
  70. label dummy4 "--------------------------------------------------------" align:#left
  71. button btn_export "Export selected objects"
  72. )
  73. -------------------------------------------------------------------------------------
  74. -- Dump vertices
  75. function DumpVertices src =
  76. (
  77. Format "\"vertices\": [" to:ostream
  78. num = src.count
  79. if num > 0 then
  80. (
  81. for i = 1 to num do
  82. (
  83. vert = src[i]
  84. if flipYZ.checked then
  85. (
  86. x = vert.x
  87. y = vert.z
  88. z = vert.y
  89. z *= -1
  90. )
  91. else
  92. (
  93. x = vert.x
  94. y = vert.y
  95. z = vert.z
  96. )
  97. Format vertexFormat x y z to:ostream
  98. if i < num then Format "," to:ostream
  99. )
  100. )
  101. Format "],\n\n" to:ostream
  102. )
  103. -------------------------------------------------------------------------------------
  104. -- Dump colors
  105. function DumpColors src useColors =
  106. (
  107. Format "\"colors\": [" to:ostream
  108. num = src.count
  109. if num > 0 and useColors then
  110. (
  111. for i = 1 to num do
  112. (
  113. col = src[i]
  114. r = col.r as Integer
  115. g = col.g as Integer
  116. b = col.b as Integer
  117. hexNum = ( bit.shift r 16 ) + ( bit.shift g 8 ) + b
  118. -- hexColor = formattedPrint hexNum format:"#x"
  119. -- Format "%" hexColor to:ostream
  120. decColor = formattedPrint hexNum format:"#d"
  121. Format "%" decColor to:ostream
  122. if i < num then Format "," to:ostream
  123. )
  124. )
  125. Format "],\n\n" to:ostream
  126. )
  127. -------------------------------------------------------------------------------------
  128. -- Dump normals
  129. function DumpNormals src =
  130. (
  131. Format "\"normals\": [" to:ostream
  132. num = src.count
  133. if num > 0 and exportNormal.checked then
  134. (
  135. for i = 1 to num do
  136. (
  137. normal = src[i]
  138. normal = normalize normal as point3
  139. if flipYZ.checked then
  140. (
  141. x = normal.x
  142. y = normal.z
  143. z = normal.y
  144. z *= -1
  145. )
  146. else
  147. (
  148. x = normal.x
  149. y = normal.y
  150. z = normal.z
  151. )
  152. Format vertexNormalFormat x y z to:ostream
  153. if i < num then Format "," to:ostream
  154. )
  155. )
  156. Format "],\n\n" to:ostream
  157. )
  158. -------------------------------------------------------------------------------------
  159. -- Dump uvs
  160. function DumpUvs src =
  161. (
  162. Format "\"uvs\": [[" to:ostream
  163. num = src.count
  164. if num > 0 and exportUv.checked then
  165. (
  166. for i = 1 to num do
  167. (
  168. uvw = src[i]
  169. u = uvw.x
  170. if flipUV.checked then
  171. (
  172. v = 1 - uvw.y
  173. )
  174. else
  175. (
  176. v = uvw.y
  177. )
  178. Format UVFormat u v to:ostream
  179. if i < num then Format "," to:ostream
  180. )
  181. )
  182. Format "]],\n\n" to:ostream
  183. )
  184. -------------------------------------------------------------------------------------
  185. -- Dump faces
  186. function DumpFaces src useColors =
  187. (
  188. Format "\"faces\": [" to:ostream
  189. num = src.count
  190. if num > 0 then
  191. (
  192. for i = 1 to num do
  193. (
  194. zface = src[i]
  195. fv = zface[1]
  196. fuv = zface[2]
  197. m = zface[3] - 1
  198. fc = zface[4]
  199. needsFlip = zface[5]
  200. isTriangle = true
  201. hasMaterial = true
  202. hasFaceUvs = false
  203. hasFaceVertexUvs = ((classof fuv == Point3) and exportUv.checked)
  204. hasFaceNormals = false
  205. hasFaceVertexNormals = (exportNormal.checked)
  206. hasFaceColors = false
  207. hasFaceVertexColors = ((classof fc == Point3) and useColors)
  208. faceType = 0
  209. faceType = bit.set faceType 1 (not isTriangle)
  210. faceType = bit.set faceType 2 hasMaterial
  211. faceType = bit.set faceType 3 hasFaceUvs
  212. faceType = bit.set faceType 4 hasFaceVertexUvs
  213. faceType = bit.set faceType 5 hasFaceNormals
  214. faceType = bit.set faceType 6 hasFaceVertexNormals
  215. faceType = bit.set faceType 7 hasFaceColors
  216. faceType = bit.set faceType 8 hasFaceVertexColors
  217. if i > 1 then
  218. (
  219. Format "," faceType to:ostream
  220. )
  221. Format "%" faceType to:ostream
  222. if isTriangle then
  223. (
  224. va = (fv.x - 1) as Integer
  225. vb = (fv.y - 1) as Integer
  226. vc = (fv.z - 1) as Integer
  227. if flipFace.checked or needsFlip then
  228. (
  229. tmp = vb
  230. vb = vc
  231. vc = tmp
  232. )
  233. Format ",%,%,%" va vb vc to:ostream
  234. if hasMaterial then
  235. (
  236. Format ",%" m to:ostream
  237. )
  238. if hasFaceVertexUvs then
  239. (
  240. ua = (fuv.x - 1) as Integer
  241. ub = (fuv.y - 1) as Integer
  242. uc = (fuv.z - 1) as Integer
  243. if flipFace.checked or needsFlip then
  244. (
  245. tmp = ub
  246. ub = uc
  247. uc = tmp
  248. )
  249. Format ",%,%,%" ua ub uc to:ostream
  250. )
  251. if hasFaceVertexNormals then
  252. (
  253. if smoothNormal.checked then
  254. (
  255. -- normals have the same indices as vertices
  256. na = va
  257. nb = vb
  258. nc = vc
  259. )
  260. else
  261. (
  262. -- normals have the same indices as face
  263. na = i - 1
  264. nb = na
  265. nc = na
  266. )
  267. if flipFace.checked or needsFlip then
  268. (
  269. tmp = nb
  270. nb = nc
  271. nc = tmp
  272. )
  273. Format ",%,%,%" na nb nc to:ostream
  274. )
  275. if hasFaceVertexColors then
  276. (
  277. ca = (fc.x - 1) as Integer
  278. cb = (fc.y - 1) as Integer
  279. cc = (fc.z - 1) as Integer
  280. if flipFace.checked or needsFlip then
  281. (
  282. tmp = cb
  283. cb = cc
  284. cc = tmp
  285. )
  286. Format ",%,%,%" ca cb cc to:ostream
  287. )
  288. )
  289. )
  290. )
  291. Format "]" to:ostream
  292. )
  293. -------------------------------------------------------------------------------------
  294. -- Dump color
  295. function DumpColor pcolor label =
  296. (
  297. r = pcolor.r / 255
  298. g = pcolor.g / 255
  299. b = pcolor.b / 255
  300. fr = formattedPrint r format:".4f"
  301. fg = formattedPrint g format:".4f"
  302. fb = formattedPrint b format:".4f"
  303. Format "\"%\" : [%, %, %],\n" label fr fg fb to:ostream
  304. )
  305. -------------------------------------------------------------------------------------
  306. -- Dump map
  307. function DumpMap pmap label =
  308. (
  309. if classof pmap == BitmapTexture then
  310. (
  311. bm = pmap.bitmap
  312. if bm != undefined then
  313. (
  314. fname = filenameFromPath bm.filename
  315. Format "\"%\" : \"skins/%\",\n" label fname to:ostream
  316. )
  317. )
  318. )
  319. -------------------------------------------------------------------------------------
  320. -- Dump bones
  321. -- src = #( #(index, name, position, scale, rotation), .. )
  322. -- boneOrder lists the correct output order of the bones
  323. -- newIndices is inverse of boneOrder
  324. function DumpBones src boneOrder newIndices =
  325. (
  326. numBones = boneOrder.count
  327. Format ",\n\n\t\"bones\" : [\n" to:ostream
  328. for i = 1 to numBones do
  329. (
  330. b = src[boneOrder[i]]
  331. if b[1] == -1 then
  332. (
  333. parent_index = -1
  334. ) else (
  335. parent_index = newIndices[b[1]+1]
  336. )
  337. bone_name = b[2]
  338. p = b[3]
  339. s = b[4]
  340. r = b[5]
  341. Format boneFormat parent_index bone_name p s r.x r.y r.z r.w to:ostream
  342. if (i < numBones) then (Format "," to:ostream)
  343. Format "\n\n" to:ostream
  344. )
  345. Format "\t],\n\n" to:ostream
  346. )
  347. -------------------------------------------------------------------------------------
  348. -- Dump skin indices
  349. -- src = #( #(skinned?, #(index1A, index1B, ..), name )
  350. -- If the mesh wasn't skinned, look in boneNames for its parent to fix the index
  351. -- If it's not there, leave as 0
  352. -- boneOrder lists the correct output order of the bones
  353. -- newIndices is inverse of boneOrder
  354. function DumpIndices src boneNames newIndices =
  355. (
  356. output = #()
  357. for i=1 to src.count do
  358. (
  359. if src[i][1] then
  360. (
  361. join output src[i][2]
  362. ) else (
  363. bone = findItem boneNames src[i][3]
  364. for j=1 to src[i][2].count do
  365. (
  366. src[i][2][j] = bone
  367. )
  368. join output src[i][2]
  369. )
  370. )
  371. Format "\t\"skinIndices\" : [" to:ostream
  372. num = output.count
  373. if num > 0 then
  374. (
  375. for i = 1 to num do
  376. (
  377. Format "%" (newIndices[output[i] + 1]) to:ostream
  378. if i < num then
  379. (
  380. Format "," to:ostream
  381. )
  382. )
  383. )
  384. Format "],\n\n" to:ostream
  385. )
  386. -------------------------------------------------------------------------------------
  387. -- Dump skin weights
  388. -- src = #( weight1, weight2, .. )
  389. function DumpWeights src =
  390. (
  391. Format "\t\"skinWeights\" : [" to:ostream
  392. num = src.count
  393. if num > 0 then
  394. (
  395. for i = 1 to num do
  396. (
  397. Format "%" src[i] to:ostream
  398. if i < num then Format "," to:ostream
  399. )
  400. )
  401. Format "],\n\n" to:ostream
  402. )
  403. -------------------------------------------------------------------------------------
  404. -- Dump the keyframes for every bone
  405. -- src = #( #( parent, #( time, #( posx, posy, posz ), rot, scl ), .. ), .. )
  406. -- ||---Bone-- |---------------Keyframe----------------| ----||
  407. -- boneOrder lists the correct output order of the bones
  408. -- newIndices is inverse of boneOrder
  409. function DumpKeyframes src boneOrder newIndices fps =
  410. (
  411. Format animHeaderFormat fps src[1][2][src[1][2].count][1] to:ostream
  412. numBones = boneOrder.count
  413. for i = 1 to (numBones) do
  414. (
  415. if (src[boneOrder[i]][1] == -1) then
  416. (
  417. parent_index = -1
  418. ) else
  419. (
  420. parent_index = newIndices[src[boneOrder[i]][1]+1]
  421. )
  422. Format animBoneHeaderFormat parent_index to:ostream
  423. bnkeys = src[boneOrder[i]][2]
  424. for j = 1 to bnkeys.count do
  425. (
  426. Format keyFormat bnkeys[j][1] bnkeys[j][2][1] bnkeys[j][2][2] bnkeys[j][2][3] bnkeys[j][3].x bnkeys[j][3].y bnkeys[j][3].z bnkeys[j][3].w bnkeys[j][4] to:ostream
  427. if j < bnkeys.count then Format "," to:ostream
  428. Format "\n" to:ostream
  429. )
  430. Format animBoneFooterFormat to:ostream
  431. if i < (numBones) then
  432. (
  433. Format "," to:ostream
  434. )
  435. Format "\n" to:ostream
  436. )
  437. Format animFooterFormat to:ostream
  438. )
  439. -------------------------------------------------------------------------------------
  440. -- Dump the morphtargets
  441. -- src = #( #( #(index, name, vertices = #( #( x,y,z ), .. ) ), .. ), .. )
  442. -- |List of meshes ----------------------------------------------|
  443. -- |- |List of targets: only one mesh may have multiple ---| ----|
  444. -- |- |- |Individual target(s) ----------------------| ----| ----|
  445. function DumpMorphTargets src =
  446. (
  447. -- This procedure assumes that only one element of src has actual morph targets.
  448. -- The targets field of the other elements is used to store the vertices of static meshes.
  449. -- These vertices are duplicated and joined with the vertices of the actual morph targets.
  450. -- Initialize with whatever happens to be first
  451. output = src[1]
  452. for m=2 to src.count do
  453. (
  454. if (src[m].count == 1) then
  455. (
  456. -- This is a static mesh; attach its vertices, but do nothing else.
  457. for t=1 to output.count do
  458. (
  459. join output[t][3] src[m][1][3]
  460. )
  461. ) else (
  462. -- This mesh contains morph targets.
  463. -- Duplicate the static vertices, join with each morph target, and set the indices and names.
  464. while ( output.count < src[m].count ) do
  465. (
  466. -- Duplicate vertices
  467. append output (deepCopy output[1])
  468. )
  469. for t=1 to src[m].count do
  470. (
  471. -- Vertices
  472. join output[t][3] src[m][t][3]
  473. -- Index, name
  474. output[t][1] = src[m][t][1]
  475. output[t][2] = src[m][t][2]
  476. )
  477. )
  478. )
  479. Format "\"morphTargets\": [" to:ostream
  480. for k=1 to output.count do
  481. (
  482. target = output[k]
  483. Format "{ \"name\": \"morph_%\", \"vertices\": [" target[2] to:ostream
  484. vertices = target[3]
  485. for j=1 to vertices.count do
  486. (
  487. Format "%,%,%" vertices[j][1] vertices[j][2] vertices[j][3] to:ostream
  488. if (j != vertices.count) then
  489. (
  490. Format "," to:ostream
  491. )
  492. )
  493. Format "] }" to:ostream
  494. if (k != output.count) then
  495. (
  496. Format ",\n" to:ostream
  497. )
  498. )
  499. Format "],\n" to:ostream
  500. )
  501. -------------------------------------------------------------------------------------
  502. -- Export materials
  503. function ExportMaterials zmaterials zcolors =
  504. (
  505. Format "\"materials\": [\n" to:ostream
  506. totalMaterials = zmaterials.count
  507. for i = 1 to totalMaterials do
  508. (
  509. mat = zmaterials[i]
  510. Format "{\n" to:ostream
  511. -- debug
  512. Format "\"DbgIndex\" : %,\n" (i-1) to:ostream
  513. if classof mat != BooleanClass then
  514. (
  515. useVertexColors = zcolors[i]
  516. Format "\"DbgName\" : \"%\",\n" mat.name to:ostream
  517. -- colors
  518. DumpColor mat.diffuse "colorDiffuse"
  519. DumpColor mat.ambient "colorAmbient"
  520. DumpColor mat.specular "colorSpecular"
  521. t = mat.opacity / 100
  522. s = mat.glossiness
  523. Format "\"transparency\" : %,\n" t to:ostream
  524. Format "\"specularCoef\" : %,\n" s to:ostream
  525. -- maps
  526. DumpMap mat.diffuseMap "mapDiffuse"
  527. DumpMap mat.ambientMap "mapAmbient"
  528. DumpMap mat.specularMap "mapSpecular"
  529. DumpMap mat.bumpMap "mapBump"
  530. DumpMap mat.opacityMap "mapAlpha"
  531. )
  532. else
  533. (
  534. useVertexColors = false
  535. Format "\"DbgName\" : \"%\",\n" "dummy" to:ostream
  536. DumpColor red "colorDiffuse"
  537. )
  538. Format "\"vertexColors\" : %\n" useVertexColors to:ostream
  539. Format "}" to:ostream
  540. if ( i < totalMaterials ) then Format "," to:ostream
  541. Format "\n\n" to:ostream
  542. )
  543. Format "],\n\n" to:ostream
  544. )
  545. -------------------------------------------------------------------------------------
  546. -- Extract vertices from mesh
  547. function ExtractVertices obj whereto =
  548. (
  549. n = obj.numVerts
  550. for i = 1 to n do
  551. (
  552. v = GetVert obj i
  553. append whereto v
  554. )
  555. )
  556. -------------------------------------------------------------------------------------
  557. -- Extract vertex colors from mesh
  558. function ExtractColors obj whereto =
  559. (
  560. nColors = GetNumCPVVerts obj
  561. if nColors > 0 then
  562. (
  563. for i = 1 to nColors do
  564. (
  565. c = GetVertColor obj i
  566. append whereto c
  567. )
  568. )
  569. )
  570. -------------------------------------------------------------------------------------
  571. -- Extract normals from mesh
  572. function ExtractNormals obj whereto needsFlip =
  573. (
  574. if smoothNormal.checked then
  575. (
  576. num = obj.numVerts
  577. for i = 1 to num do
  578. (
  579. n = GetNormal obj i
  580. if flipFace.checked or needsFlip then
  581. (
  582. n.x *= -1
  583. n.y *= -1
  584. n.z *= -1
  585. )
  586. append whereto n
  587. )
  588. )
  589. else
  590. (
  591. num = obj.numFaces
  592. for i = 1 to num do
  593. (
  594. n = GetFaceNormal obj i
  595. if flipFace.checked or needsFlip then
  596. (
  597. n.x *= -1
  598. n.y *= -1
  599. n.z *= -1
  600. )
  601. append whereto n
  602. )
  603. )
  604. )
  605. -------------------------------------------------------------------------------------
  606. -- Extract uvs from mesh
  607. function ExtractUvs obj whereto =
  608. (
  609. n = obj.numTVerts
  610. for i = 1 to n do
  611. (
  612. v = GetTVert obj i
  613. append whereto v
  614. )
  615. )
  616. -------------------------------------------------------------------------------------
  617. -- Extract faces from mesh
  618. function ExtractFaces objMesh objMaterial whereto allMaterials needsFlip hasVColors offsetVert offsetUv offsetColor =
  619. (
  620. n = objMesh.numFaces
  621. hasUVs = objMesh.numTVerts > 0
  622. useMultiMaterial = false
  623. materialIDList = #()
  624. materialClass = classof objMaterial
  625. if materialClass == StandardMaterial then
  626. (
  627. fm = findItem allMaterials objMaterial
  628. )
  629. else if materialClass == MultiMaterial then
  630. (
  631. useMultiMaterial = true
  632. for i = 1 to n do
  633. (
  634. mID = GetFaceMatID objMesh i
  635. materialIndex = findItem objMaterial.materialIDList mID
  636. if materialIndex > 0 then
  637. (
  638. subMaterial = objMaterial.materialList[materialIndex]
  639. mMergedIndex = findItem allMaterials subMaterial
  640. if mMergedIndex > 0 then
  641. (
  642. materialIDList[mID] = mMergedIndex
  643. )
  644. else
  645. (
  646. materialIDList[mID] = findItem allMaterials false
  647. )
  648. )
  649. else
  650. (
  651. materialIDList[mID] = findItem allMaterials false
  652. )
  653. )
  654. )
  655. else
  656. (
  657. -- undefined material
  658. fm = findItem allMaterials false
  659. )
  660. for i = 1 to n do
  661. (
  662. zface = #()
  663. fv = GetFace objMesh i
  664. fv.x += offsetVert
  665. fv.y += offsetVert
  666. fv.z += offsetVert
  667. if useMultiMaterial then
  668. (
  669. mID = GetFaceMatID objMesh i
  670. fm = materialIDList[mID]
  671. )
  672. if hasUVs then
  673. (
  674. fuv = GetTVFace objMesh i
  675. fuv.x += offsetUv
  676. fuv.y += offsetUv
  677. fuv.z += offsetUv
  678. )
  679. else
  680. (
  681. fuv = false
  682. )
  683. if hasVColors then
  684. (
  685. fc = GetVCFace objMesh i
  686. fc.x += offsetColor
  687. fc.y += offsetColor
  688. fc.z += offsetColor
  689. )
  690. else
  691. (
  692. fc = false
  693. )
  694. append zface fv
  695. append zface fuv
  696. append zface fm
  697. append zface fc
  698. append zface needsFlip
  699. append whereto zface
  700. )
  701. )
  702. -------------------------------------------------------------------------------------
  703. -- Extract materials from eventual multi-material
  704. function ExtractMaterials objMesh objMaterial whereto wheretoColors zname hasVColors =
  705. (
  706. materialClass = classof objMaterial
  707. if materialClass == StandardMaterial then
  708. (
  709. if ( findItem whereto objMaterial ) == 0 then
  710. (
  711. append whereto objMaterial
  712. append wheretoColors hasVColors
  713. )
  714. )
  715. else if materialClass == MultiMaterial then
  716. (
  717. n = objMesh.numFaces
  718. for i = 1 to n do
  719. (
  720. mID = getFaceMatId objMesh i
  721. materialIndex = findItem objMaterial.materialIDList mID
  722. if materialIndex > 0 then
  723. (
  724. subMaterial = objMaterial.materialList[materialIndex]
  725. if ( findItem whereto subMaterial ) == 0 then
  726. (
  727. append whereto subMaterial
  728. append wheretoColors hasVColors
  729. )
  730. )
  731. )
  732. )
  733. else
  734. (
  735. -- unknown or undefined material
  736. append whereto false
  737. append wheretoColors false
  738. )
  739. )
  740. -------------------------------------------------------------------------------------
  741. -- Hack to figure out if normals are messed up
  742. function NeedsFaceFlip node =
  743. (
  744. needsFlip = false
  745. local tmp = Snapshot node
  746. face_normal = normalize ( getfacenormal tmp 1 )
  747. face = getface tmp 1
  748. va = getvert tmp face[1]
  749. vb = getvert tmp face[2]
  750. vc = getvert tmp face[3]
  751. computed_normal = normalize ( cross (vc - vb) (va - vb) )
  752. if distance computed_normal face_normal > 0.1 then needsFlip = true
  753. delete tmp
  754. return needsFlip
  755. )
  756. -------------------------------------------------------------------------------------
  757. -- Extract only things that either already are or can be converted to meshes
  758. function ExtractMesh node =
  759. (
  760. if SuperClassOf node == GeometryClass then
  761. (
  762. needsFlip = false
  763. hasVColors = false
  764. zmesh = SnapshotAsMesh node
  765. if autoflipFace.checked then
  766. (
  767. needsFlip = NeedsFaceFlip node
  768. )
  769. if exportColor.checked and ( getNumCPVVerts zmesh ) > 0 then
  770. (
  771. hasVColors = true
  772. )
  773. return #( zmesh, node.name, node.material, needsFlip, hasVColors )
  774. )
  775. -- Not geometry ... could be a camera, light, etc.
  776. return #( false, node.name, 0, false, false )
  777. )
  778. -------------------------------------------------------------------------------------
  779. -- Extract the morph targets
  780. -- whereto = #( #( #(index, name, vertices = #( #( x,y,z ), .. ) ), .. ), .. )
  781. -- |List of meshes -----------------------------------------------|
  782. -- |- |List of targets -------------------------------------| ----|
  783. -- |- |- |Individual target --------------------------| ----| ----|
  784. function ExtractMorphTargets node whereto &morphFlag =
  785. (
  786. targets = #()
  787. morphs = #()
  788. if ( node.modifiers[#morpher] != undefined ) then (
  789. -- Export the morph target, if one exists
  790. morphFlag = true
  791. for i=1 to 100 do
  792. (
  793. nPts = WM3_MC_NumMPts node.morpher i
  794. if (nPts > 0) then
  795. (
  796. append targets #(i, nPts)
  797. )
  798. )
  799. --Set all to zero
  800. for k=1 to targets.count do
  801. (
  802. i = targets[k][1]
  803. node.morpher[i].controller.value = 0
  804. )
  805. --Max out one at a time, record it, then zero out again
  806. for k=1 to targets.count do
  807. (
  808. i = targets[k][1]
  809. numVerts = targets[k][2]
  810. name = WM3_MC_GetName node.morpher i
  811. verts = #()
  812. node.morpher[i].controller.value = 100
  813. for j = 1 to numVerts do
  814. (
  815. p = GetVert node j
  816. append verts #(p.x, p.y, p.z)
  817. )
  818. node.morpher[i].controller.value = 0
  819. append morphs #(i, name, verts)
  820. )
  821. append whereto morphs
  822. ) else (
  823. -- Export the mesh vertices as a dummy morph target
  824. verts = #()
  825. for k=1 to node.numVerts do
  826. (
  827. p = GetVert node k
  828. append verts #(p.x, p.y, p.z)
  829. )
  830. dummy = #()
  831. append dummy #(0, "DUMMY", verts)
  832. append whereto dummy
  833. )
  834. )
  835. -------------------------------------------------------------------------------------
  836. -- Transforms the matrix of a bone into its parent space, if a parent exists.
  837. function thinkLocally bone_node localForm =
  838. (
  839. localForm = bone_node.transform
  840. if ( bone_node.parent != undefined ) then
  841. (
  842. parentForm = bone_node.parent.transform
  843. localForm = localForm * inverse parentForm
  844. )
  845. newLocal = matrix3 1
  846. px = localForm.translationpart.x
  847. py = localForm.translationpart.y
  848. pz = localForm.translationpart.z
  849. lTran = transMatrix (localForm.translationpart)
  850. lRot = (inverse localForm.rotationpart) as matrix3
  851. lScale = scaleMatrix localForm.scalepart
  852. localForm = lScale * lRot * lTran * newLocal
  853. localForm
  854. )
  855. -------------------------------------------------------------------------------------
  856. -- Extract bones and keyframes
  857. function ExtractAnimation node bones keyframes FPS bone_names &skinFlag =
  858. (
  859. if node.modifiers[#skin] != undefined then
  860. (
  861. skinFlag = true
  862. ---------------------------------------------------------------------------------
  863. -- A dummy root bone is first created and roatated to orient the model
  864. p = (matrix3 1).translationpart
  865. s = (matrix3 1).scalepart
  866. r = (matrix3 1).rotationpart
  867. append bones #(-1,"flipRoot",p,s,r)
  868. /*
  869. if (flipYZ.checked) then
  870. (
  871. r = threeMatrix.rotationpart
  872. ) else (
  873. r = (matrix3 1).rotationpart
  874. )
  875. */
  876. r = threeMatrix.rotationpart
  877. root_keys = #(#(0, p, r, s))
  878. slidertime = 0
  879. while (slidertime < animationrange.end) do
  880. (
  881. slidertime += 1
  882. sTime = (slidertime / FPS) as String
  883. append root_keys #(substring sTime 1 (sTime.count - 1), p, r, s)
  884. )
  885. append keyframes #(-1, root_keys)
  886. ---------------------------------------------------------------------------------
  887. -- The model's bones and keyframes are then extracted
  888. max modify mode
  889. total_bones = skinops.getnumberbones node.modifiers[#skin]
  890. vertex_count = getNumverts node
  891. -- Find parents by looking up their names; bone names MUST be unique
  892. -- Can't guarantee that parent will be read before child; store all names beforehand
  893. for i = 1 to total_bones do
  894. (
  895. bone_name = skinops.getbonename node.modifiers[#skin] i 0
  896. append bone_names bone_name
  897. )
  898. for i = 1 to total_bones do
  899. (
  900. slidertime = 0
  901. bone_name = skinops.getbonename node.modifiers[#skin] i 0
  902. bone_node = getNodeByName bone_name
  903. parent_index = 0
  904. if ( bone_node.parent != undefined ) then
  905. (
  906. parent_name = bone_node.parent.name
  907. parent_index = (findItem bone_names parent_name)
  908. )
  909. localForm = bone_node.transform
  910. localForm = thinkLocally bone_node localForm
  911. p = localForm.translationpart
  912. r = localForm.rotationpart
  913. s = localForm.scalepart
  914. append bones #(parent_index, bone_name, p, bone_node.transform.scalepart, r)
  915. in coordsys parent bone_keys = #(#(0, p, r, bone_node.transform.scalepart))
  916. while (slidertime < animationrange.end) do
  917. (
  918. slidertime += 1
  919. sTime = (slidertime / FPS) as String
  920. localForm = bone_node.transform
  921. localForm = thinkLocally bone_node localForm
  922. p = localForm.translationpart
  923. r = localForm.rotationpart
  924. s = localForm.translationpart
  925. append bone_keys #(substring sTime 1 (sTime.count - 1), p, r, bone_node.transform.scalepart)
  926. )
  927. append keyframes #(parent_index, bone_keys)
  928. )
  929. )
  930. )
  931. -------------------------------------------------------------------------------------
  932. -- Extract the skin indices and weights in one pass
  933. -- If it's a skin, skinned? = true and indices contains the bones
  934. -- If it's not, indices is dummied to #(0,..) and DumpIndices uses the parent to fix it in post
  935. -- indices = #( #( skinned?, indices, parent), ..)
  936. function ExtractInfluences node indices weights =
  937. (
  938. vertex_count = getNumverts node
  939. meshIndices = #()
  940. if node.modifiers[#skin] != undefined then
  941. (
  942. for i = 1 to vertex_count do
  943. (
  944. -- Insane defaults for the sort; these shouldn't escape into the output
  945. index1 = -1
  946. index2 = -1
  947. weight1 = -1
  948. weight2 = -1
  949. numBones = skinOps.GetVertexWeightCount node.modifiers[#skin] i
  950. --Two passes of a bubble sort to get the 2 heaviest weights
  951. for j = 1 to numBones do
  952. (
  953. thisIndex = skinops.getVertexWeightBoneID node.modifiers[#skin] i j
  954. thisWeight = skinops.getvertexweight node.modifiers[#skin] i j
  955. if (thisWeight) > weight1 then
  956. (
  957. weight1 = thisWeight
  958. index1 = thisIndex
  959. )
  960. )
  961. for j = 1 to numBones do
  962. (
  963. thisIndex = skinops.getVertexWeightBoneID node.modifiers[#skin] i j
  964. thisWeight = skinops.getvertexweight node.modifiers[#skin] i j
  965. if ((thisWeight > weight2) and (thisIndex != index1)) then
  966. (
  967. weight2 = thisWeight
  968. index2 = thisIndex
  969. )
  970. )
  971. -- Establish legal defaults: no weight from the root
  972. if (index1 == -1) then
  973. (
  974. index1 = 0
  975. weight1 = 0
  976. )
  977. if (index2 == -1) then
  978. (
  979. index2 = 0
  980. weight2 = 0
  981. )
  982. append meshIndices (index1)
  983. append meshIndices (index2)
  984. append weights weight1
  985. append weights weight2
  986. )
  987. append indices #(true, meshIndices, "ROOT")
  988. ) else (
  989. for i = 1 to vertex_count do
  990. (
  991. append meshIndices 0
  992. append meshIndices 0
  993. append weights 1
  994. append weights 1
  995. )
  996. name = "Scene Root"
  997. if node.parent != undefined then
  998. (
  999. name = node.parent.name
  1000. )
  1001. append indices #(false, meshIndices, name)
  1002. )
  1003. )
  1004. -------------------------------------------------------------------------------------
  1005. -- Enforce that parent is above all of its children in the output
  1006. -- This fixes several amusing bugs (mostly fingers of infinite length)
  1007. --
  1008. -- boneOrder: order to dump the bones in #(bones)
  1009. -- newIndices: new positional indices of bones
  1010. function ReorderBones bones boneOrder newIndices =
  1011. (
  1012. /*************************************************************************************
  1013. * Reorder bones
  1014. * Python function prototype:
  1015. * for i in range(n):
  1016. * for b in range(n):
  1017. * #new bone parent of bone legal
  1018. * if not inOut[b] and (parents[b] == -1 or inOut[parents[b]]):
  1019. * inOut[b] = True
  1020. * boneOrder.append(b)
  1021. * break;
  1022. *************************************************************************************/
  1023. total_bones = bones.count
  1024. -- Keeps track of which parents have been accounted for
  1025. inOut = #()
  1026. for i = 1 to total_bones do
  1027. (
  1028. append inOut false
  1029. )
  1030. rootNotAdded = true
  1031. for i = 1 to total_bones do
  1032. (
  1033. notFound = true
  1034. for b = 1 to total_bones while notFound do
  1035. (
  1036. if (inOut[b] != true) then
  1037. (
  1038. if (rootNotAdded and bones[b][1] == -1) then
  1039. (
  1040. inOut[b] = true
  1041. append boneOrder b
  1042. notFound = false
  1043. rootNotAdded = false
  1044. ) else (
  1045. if (inOut[bones[b][1] + 1]) then
  1046. (
  1047. inOut[b] = true
  1048. append boneOrder b
  1049. notFound = false
  1050. )
  1051. )
  1052. )
  1053. )
  1054. )
  1055. -- Takes original bone index/parent + 1, returns new correct index for parent, skinIndices, etc
  1056. for i=1 to total_bones do
  1057. (
  1058. newIndices[boneOrder[i]] = i - 1
  1059. )
  1060. )
  1061. -------------------------------------------------------------------------------------
  1062. -- Export scene
  1063. --
  1064. -- This will BREAK in HORRIBLE WAYS if you feed it more than one object for now.
  1065. function ExportScene =
  1066. (
  1067. -- Extract meshes
  1068. meshObjects = #()
  1069. mergedVertices = #()
  1070. mergedNormals = #()
  1071. mergedColors = #()
  1072. mergedUvs = #()
  1073. mergedFaces = #()
  1074. mergedMaterials = #()
  1075. mergedMaterialsColors = #()
  1076. sceneHasVColors = false
  1077. hasSkin = false
  1078. bones = #()
  1079. keyframes = #()
  1080. influences = #()
  1081. weights = #()
  1082. boneOrder = #()
  1083. newIndices = #()
  1084. bone_names = #()
  1085. hasMorph = false
  1086. mergedMorphTargets = #()
  1087. -- The horrible hackery that is skinops requires only one object be selected.
  1088. original_selection = #()
  1089. for obj in selection do
  1090. (
  1091. append original_selection obj.name
  1092. )
  1093. max select none
  1094. for name in original_selection do
  1095. (
  1096. obj = getnodebyname name
  1097. select obj
  1098. result = ExtractMesh obj
  1099. meshObj = result[1]
  1100. if ClassOf meshObj == TriMesh then
  1101. (
  1102. meshName = result[2]
  1103. meshMaterial = result[3]
  1104. needsFlip = result[4]
  1105. hasVColors = result[5]
  1106. sceneHasVColors = sceneHasVColors or hasVColors
  1107. append meshObjects result
  1108. vertexOffset = mergedVertices.count
  1109. uvOffset = mergedUvs.count
  1110. colorOffset = mergedColors.count
  1111. ExtractMaterials meshObj meshMaterial mergedMaterials mergedMaterialsColors meshName hasVColors
  1112. ExtractVertices meshObj mergedVertices
  1113. ExtractNormals meshObj mergedNormals needsFlip
  1114. ExtractColors meshObj mergedColors
  1115. ExtractUvs meshObj mergedUvs
  1116. ExtractFaces meshObj meshMaterial mergedFaces mergedMaterials needsFlip hasVColors vertexOffset uvOffset colorOffset
  1117. ExtractAnimation obj bones keyframes fps.value bone_names &hasSkin
  1118. ExtractInfluences obj influences weights
  1119. ReorderBones bones boneOrder newIndices
  1120. ExtractMorphTargets obj mergedMorphTargets &hasMorph
  1121. )
  1122. max select none
  1123. )
  1124. totalVertices = mergedVertices.count
  1125. totalFaces = mergedFaces.count
  1126. totalMaterials = mergedMaterials.count
  1127. totalColors = 0
  1128. totalNormals = 0
  1129. totalUvs = 0
  1130. useColors = false
  1131. if sceneHasVColors and exportColor.checked then
  1132. (
  1133. totalColors = mergedColors.count
  1134. useColors = true
  1135. )
  1136. if exportNormal.checked then
  1137. (
  1138. totalNormals = mergedNormals.count
  1139. )
  1140. if exportUv.checked then
  1141. (
  1142. totalUvs = mergedUvs.count
  1143. )
  1144. -- Dump model
  1145. Format "{\n\n" to:ostream
  1146. -- Dump header
  1147. Format headerFormat maxFileName totalVertices totalNormals totalColors totalUvs totalFaces totalMaterials to:ostream
  1148. -- Dump all materials in the scene
  1149. ExportMaterials mergedMaterials mergedMaterialsColors
  1150. -- Dump merged data from all selected geometries
  1151. DumpVertices mergedVertices
  1152. if hasMorph then
  1153. (
  1154. DumpMorphTargets mergedMorphTargets
  1155. )
  1156. DumpNormals mergedNormals
  1157. DumpColors mergedColors useColors
  1158. DumpUvs mergedUvs
  1159. DumpFaces mergedFaces useColors
  1160. if hasSkin then
  1161. (
  1162. DumpBones bones boneOrder newIndices
  1163. DumpIndices influences bone_names newIndices
  1164. DumpWeights weights
  1165. DumpKeyframes keyframes boneOrder newIndices fps.value
  1166. )
  1167. -- Dump footer
  1168. Format footerFormat to:ostream
  1169. )
  1170. -------------------------------------------------------------------------------------
  1171. -- Open and prepare a file handle for writing
  1172. function GetSaveFileStream =
  1173. (
  1174. zname = getFilenameFile maxFileName
  1175. zname += ".js"
  1176. fname = GetSaveFileName filename:zname types:"JavaScript file (*.js)|*.js|All Files(*.*)|*.*|"
  1177. if fname == undefined then
  1178. (
  1179. return undefined
  1180. )
  1181. ostream = CreateFile fname
  1182. if ostream == undefined then
  1183. (
  1184. MessageBox "Couldn't open file for writing !"
  1185. return undefined
  1186. )
  1187. return ostream
  1188. )
  1189. -------------------------------------------------------------------------------------
  1190. -- Export button click handler
  1191. on btn_export pressed do
  1192. (
  1193. ostream = GetSaveFileStream()
  1194. if ostream != undefined then
  1195. (
  1196. ExportScene()
  1197. close ostream
  1198. )
  1199. )
  1200. )
  1201. createDialog ThreeJSExporter width:300