assimp.monkey2 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. Namespace mojo3d.assimp
  2. Struct aiVector3D Extension
  3. Operator To:Vec3f()
  4. Return New Vec3f( x,y,z )
  5. End
  6. End
  7. Struct aiQuaternion Extension
  8. Operator To:Quatf()
  9. Return New Quatf( x,y,z,-w )
  10. End
  11. End
  12. Struct aiMatrix4x4 Extension
  13. Operator To:Mat4f()
  14. Return New Mat4f(
  15. New Vec4f( a1,b1,c1,d1 ),
  16. New Vec4f( a2,b2,c2,d2 ),
  17. New Vec4f( a3,b3,c3,d3 ),
  18. New Vec4f( a4,b4,c4,d4 ) )
  19. End
  20. Operator To:AffineMat4f()
  21. ' If d1<>0 Or d2<>0 Or d3<>0 Or d4<>1 Print "WARNING! Assimp node matrix is not affine! d1="+d1+", d2="+d2+", d3="+d3+", d4="+d4
  22. Return New AffineMat4f(
  23. New Vec3f( a1,b1,c1 ),
  24. New Vec3f( a2,b2,c2 ),
  25. New Vec3f( a3,b3,c3 ),
  26. New Vec3f( a4,b4,c4 ) )
  27. End
  28. End
  29. Class AssimpLoader
  30. Method New( scene:aiScene,dir:String )
  31. _scene=scene
  32. _dir=dir
  33. End
  34. Method LoadMesh:Mesh()
  35. Local mesh:=New Mesh
  36. Local materials:=New Stack<Material>
  37. For Local i:=0 Until _scene.mNumMeshes
  38. Local aimesh:=_scene.mMeshes[i]
  39. If i=0 mesh.AddMaterials( 1 )
  40. LoadMesh( aimesh,mesh,Null,False )
  41. Next
  42. mesh.UpdateTangents()
  43. Return mesh
  44. End
  45. Method LoadModel:Model()
  46. Local mesh:=New Mesh
  47. Local materials:=New Stack<Material>
  48. For Local i:=0 Until _scene.mNumMeshes
  49. Local aimesh:=_scene.mMeshes[i]
  50. mesh.AddMaterials( 1 )
  51. LoadMesh( aimesh,mesh,Null,False )
  52. materials.Push( LoadMaterial( aimesh,false ) )
  53. Next
  54. Local model:=New Model
  55. If materials.Length
  56. mesh.UpdateTangents()
  57. model.Mesh=mesh
  58. model.Materials=materials.ToArray()
  59. Endif
  60. Return model
  61. End
  62. Method LoadBonedModel:Model()
  63. Local model:=New Model
  64. CreateNodes( _scene.mRootNode,model )
  65. LoadNodes( _scene.mRootNode )
  66. LoadAnimator( model )
  67. Return model
  68. End
  69. Method LoadAnimation:Animation()
  70. If Not _scene.mNumAnimations Return Null
  71. _nodes["<null>"]=Null
  72. _entityIds["<null>"]=_entities.Length
  73. _entities.Add( Null )
  74. EnumEntityIds( _scene.mRootNode )
  75. Local animation:=LoadAnimation( _scene.mAnimations[0] )
  76. Return animation
  77. End
  78. Private
  79. Field _scene:aiScene
  80. Field _dir:String
  81. Field _materials:=New Stack<Material>
  82. Field _nodes:=New StringMap<Entity>
  83. Field _entityIds:=New StringMap<Int>
  84. Field _entities:=New Stack<Entity>
  85. Method LoadBones( aimesh:aiMesh,model:Model,vertices:Vertex3f[] )
  86. Local bones:=model.Bones,i0:=bones.Length
  87. bones=bones.Resize( i0+aimesh.mNumBones )
  88. For Local i:=0 Until aimesh.mNumBones
  89. Local aibone:=aimesh.mBones[i]
  90. For Local j:=0 Until aibone.mNumWeights
  91. Local aiweight:=aibone.mWeights[j]
  92. If aiweight.mWeight<.00001 Continue
  93. Local wp:=Cast<Float Ptr>( Varptr vertices[aiweight.mVertexId].weights )
  94. Local bp:=Cast<UByte Ptr>( Varptr vertices[aiweight.mVertexId].bones )
  95. Local k:=0
  96. For k=0 Until 4
  97. If wp[k] Continue
  98. wp[k]=aiweight.mWeight
  99. bp[k]=i0+i
  100. Exit
  101. Next
  102. If k=4 Print "Too many vertex weights"
  103. Next
  104. bones[i0+i].entity=_entities[ _entityIds[ aibone.mName.data ] ]
  105. bones[i0+i].offset=Cast<AffineMat4f>( aibone.mOffsetMatrix )
  106. Next
  107. model.Bones=bones
  108. End
  109. Method LoadMesh( aimesh:aiMesh,mesh:Mesh,model:Model,boned:bool )
  110. Local vertices:=New Vertex3f[ aimesh.mNumVertices ]
  111. Local vp:=aimesh.mVertices
  112. Local np:=aimesh.mNormals
  113. Local cp:=aimesh.mColors[0]
  114. Local tp0:=aimesh.mTextureCoords[0]
  115. Local tp1:=aimesh.mTextureCoords[1]
  116. For Local i:=0 Until vertices.Length
  117. vertices[i].position=New Vec3f( vp[i].x,vp[i].y,vp[i].z )
  118. If np
  119. vertices[i].normal=New Vec3f( np[i].x,np[i].y,np[i].z )
  120. Endif
  121. If cp
  122. Local color:=cp[i]
  123. Local a:=color.a * 255.0
  124. vertices[i].color=UInt(a) Shl 24 | UInt(color.b*a) Shl 16 | UInt(color.g*a) Shl 8 | UInt(color.r*a)
  125. Endif
  126. If tp0
  127. vertices[i].texCoord0=New Vec2f( tp0[i].x,tp0[i].y )
  128. Endif
  129. If tp1
  130. vertices[i].texCoord1=New Vec2f( tp1[i].x,tp1[i].y )
  131. Endif
  132. Next
  133. Local indices:=New UInt[ aimesh.mNumFaces*3 ]
  134. Local fp:=aimesh.mFaces,v0:=mesh.NumVertices
  135. For Local i:=0 Until aimesh.mNumFaces
  136. If fp[i].mNumIndices<>3
  137. Print "not a triangle! "+fp[i].mNumIndices
  138. Endif
  139. indices[i*3+0]=fp[i].mIndices[0]+v0
  140. indices[i*3+1]=fp[i].mIndices[1]+v0
  141. indices[i*3+2]=fp[i].mIndices[2]+v0
  142. Next
  143. If model And boned And aimesh.mNumBones LoadBones( aimesh,model,vertices )
  144. mesh.AddVertices( vertices )
  145. mesh.AddTriangles( indices,mesh.NumMaterials-1 )
  146. End
  147. Method LoadMaterial:Material( aimesh:aiMesh,boned:bool )
  148. Local index:=aimesh.mMaterialIndex
  149. If index<_materials.Length And _materials[index] Return _materials[index]
  150. If index>=_materials.Length _materials.Resize( index+1 )
  151. _materials[index]=LoadMaterial( _scene.mMaterials[index],boned )
  152. Return _materials[index]
  153. End
  154. Method LoadMaterial:Material( aimaterial:aiMaterial,boned:Bool )
  155. Local ainame:aiString,name:String
  156. aiGetMaterialString( aimaterial,AI_MATKEY_NAME,0,0,Varptr ainame )
  157. name=ainame.data
  158. Local diffuseTexture:Texture=Null
  159. Local aipath:aiString,path:String
  160. aiGetMaterialTexture( aimaterial,aiTextureType_DIFFUSE,0,Varptr aipath )
  161. path=aipath.data
  162. If path
  163. path=_dir+StripDir( path )
  164. diffuseTexture=Texture.Load( path,TextureFlags.FilterMipmap|TextureFlags.WrapST )
  165. Endif
  166. Local diffuseColor:Color=Color.White
  167. Local aicolor:aiColor4D
  168. aiGetMaterialColor( aimaterial,AI_MATKEY_COLOR_DIFFUSE,0,0,Varptr aicolor )
  169. diffuseColor=New Color( Pow( aicolor.r,2.2 ),Pow( aicolor.g,2.2 ),Pow( aicolor.b,2.2 ),aicolor.a )
  170. Local material:=New PbrMaterial
  171. material.Boned=boned
  172. material.Name=name
  173. If diffuseTexture material.ColorTexture=diffuseTexture
  174. material.ColorFactor=diffuseColor
  175. Return material
  176. End
  177. Method EnumEntityIds( node:aiNode )
  178. _entityIds[ node.mName.data ]=_entityIds.Count()
  179. For Local i:=0 Until node.mNumChildren
  180. EnumEntityIds( node.mChildren[i] )
  181. Next
  182. End
  183. Method CreateNodes( node:aiNode,parent:Model )
  184. Local model:=New Model( parent )
  185. model.Name=node.mName.data
  186. model.LocalMatrix=Cast<AffineMat4f>( node.mTransformation )
  187. _nodes[ model.Name ]=model
  188. _entityIds[ model.Name ]=_entities.Length
  189. _entities.Push( model )
  190. For Local i:=0 Until node.mNumChildren
  191. CreateNodes( node.mChildren[i],model )
  192. Next
  193. End
  194. Method LoadNodes( node:aiNode )
  195. Local model:=Cast<Model>( _nodes[ node.mName.data ] )
  196. Local mesh:=New Mesh
  197. Local materials:=New Stack<Material>
  198. For Local i:=0 Until node.mNumMeshes
  199. Local aimesh:=_scene.mMeshes[ node.mMeshes[i] ]
  200. mesh.AddMaterials( 1 )
  201. Local boned:=aimesh.mNumBones>0
  202. LoadMesh( aimesh,mesh,model,boned )
  203. materials.Push( LoadMaterial( aimesh,boned ) )
  204. Next
  205. If materials.Length
  206. mesh.UpdateTangents()
  207. model.Mesh=mesh
  208. model.Materials=materials.ToArray()
  209. Endif
  210. For Local i:=0 Until node.mNumChildren
  211. LoadNodes( node.mChildren[i] )
  212. Next
  213. End
  214. Method LoadAnimationChannel:AnimationChannel( aichan:aiNodeAnim )
  215. Local posKeys:=New PositionKey[ aichan.mNumPositionKeys ]
  216. For Local i:=0 Until posKeys.Length
  217. Local aikey:=aichan.mPositionKeys[i]
  218. posKeys[i]=New PositionKey( aikey.mTime,aikey.mValue )
  219. Next
  220. Local rotKeys:=New RotationKey[ aichan.mNumRotationKeys ]
  221. For Local i:=0 Until rotKeys.Length
  222. Local aikey:=aichan.mRotationKeys[i]
  223. rotKeys[i]=New RotationKey( aikey.mTime,aikey.mValue )
  224. Next
  225. Local sclKeys:=New ScaleKey[ aichan.mNumScalingKeys ]
  226. For Local i:=0 Until sclKeys.Length
  227. Local aikey:=aichan.mScalingKeys[i]
  228. sclKeys[i]=New ScaleKey( aikey.mTime,aikey.mValue )
  229. Next
  230. Return New AnimationChannel( posKeys,rotKeys,sclKeys )
  231. End
  232. Method LoadAnimation:Animation( aianim:aiAnimation )
  233. ' Print "_entities.Length="+_entities.Length
  234. ' Print "_entityIds.Count="+_entityIds.Count()
  235. ' Print "mNumChannels="+aianim.mNumChannels
  236. Local channels:=New AnimationChannel[ _entityIds.Count() ]
  237. For Local i:=0 Until aianim.mNumChannels
  238. Local aichan:=aianim.mChannels[i]
  239. Local id:=_entityIds[ aichan.mNodeName.data ]
  240. Local channel:=LoadAnimationChannel( aichan )
  241. channels[id]=channel
  242. ' Print "channel "+id+", numposkeys="+channel.PositionKeys.Length+", numrotkeys="+channel.RotationKeys.Length+", numsclkeys="+channel.ScaleKeys.Length
  243. Next
  244. ' Print "duration="+aianim.mDuration+", mTicksPerSecond="+aianim.mTicksPerSecond
  245. Local animation:=New Animation( aianim.mName.data,channels,aianim.mDuration,aianim.mTicksPerSecond,AnimationMode.Looping )
  246. Return animation
  247. End
  248. Method LoadAnimator:Animator( entity:Entity )
  249. ' Print "mNumAnimations="+_scene.mNumAnimations
  250. If Not _scene.mNumAnimations Return Null
  251. Local animations:=New Animation[_scene.mNumAnimations]
  252. For Local i:=0 Until _scene.mNumAnimations
  253. animations[i]=LoadAnimation( _scene.mAnimations[i] )
  254. Next
  255. Local animator:=New Animator( entity )
  256. animator.Skeleton=_entities.ToArray()
  257. animator.Animations.AddAll( animations )
  258. Return animator
  259. End
  260. End
  261. Public
  262. #rem monkeydoc @hidden
  263. #End
  264. Class AssimpMojo3dLoader Extends Mojo3dLoader
  265. Const Instance:=New AssimpMojo3dLoader
  266. Method LoadMesh:Mesh( path:String ) Override
  267. Local flags:UInt=0
  268. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  269. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  270. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  271. flags|=aiProcess_GenSmoothNormals |aiProcess_FixInfacingNormals | aiProcess_Triangulate
  272. flags|=aiProcess_PreTransformVertices
  273. flags|=aiProcess_FindInvalidData
  274. flags|=aiProcess_OptimizeMeshes
  275. Local scene:=LoadScene( path,flags )
  276. If Not scene Return Null
  277. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  278. Local mesh:=loader.LoadMesh()
  279. Return mesh
  280. End
  281. Method LoadModel:Model( path:String ) Override
  282. Local flags:UInt=0
  283. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  284. ' flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  285. ' flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  286. flags|=aiProcess_JoinIdenticalVertices | aiProcess_SortByPType
  287. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  288. flags|=aiProcess_GenSmoothNormals | aiProcess_Triangulate
  289. flags|=aiProcess_PreTransformVertices
  290. flags|=aiProcess_FindInvalidData
  291. flags|=aiProcess_OptimizeMeshes
  292. Local scene:=LoadScene( path,flags )
  293. If Not scene Return Null
  294. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  295. Local model:=loader.LoadModel()
  296. Return model
  297. End
  298. Method LoadBonedModel:Model( path:String ) Override
  299. Local flags:UInt=0
  300. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  301. ' flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  302. ' flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  303. flags|=aiProcess_JoinIdenticalVertices | aiProcess_SortByPType
  304. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  305. flags|=aiProcess_GenSmoothNormals |aiProcess_Triangulate
  306. ' flags|=aiProcess_SplitByBoneCount
  307. ' flags|=aiProcess_LimitBoneWeights
  308. ' flags|=aiProcess_FindInvalidData
  309. ' flags|=aiProcess_OptimizeMeshes
  310. ' flags|=aiProcess_OptimizeGraph 'fails quite spectacularly!
  311. Local scene:=LoadScene( path,flags )
  312. If Not scene Return Null
  313. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  314. Local model:=loader.LoadBonedModel()
  315. Return model
  316. End
  317. Method LoadAnimation:Animation( path:String ) Override
  318. Local flags:UInt=0
  319. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  320. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  321. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  322. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  323. flags|=aiProcess_GenSmoothNormals |aiProcess_Triangulate
  324. ' flags|=aiProcess_SplitByBoneCount
  325. flags|=aiProcess_LimitBoneWeights
  326. flags|=aiProcess_FindInvalidData
  327. flags|=aiProcess_OptimizeMeshes
  328. ' flags|=aiProcess_OptimizeGraph 'fails quite spectacularly!
  329. Local scene:=LoadScene( path,flags )
  330. If Not scene Return Null
  331. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  332. Local animation:=loader.LoadAnimation()
  333. Return animation
  334. End
  335. Private
  336. Function LoadScene:aiScene( path:String,flags:UInt )
  337. Local props:=aiCreatePropertyStore()
  338. aiSetImportPropertyInteger( props,AI_CONFIG_PP_SBP_REMOVE,aiPrimitiveType_POINT | aiPrimitiveType_LINE )
  339. aiSetImportPropertyInteger( props,AI_CONFIG_PP_FD_REMOVE,1 )
  340. aiSetImportPropertyInteger( props,AI_CONFIG_PP_SBBC_MAX_BONES,64 )
  341. path=RealPath( path )
  342. Local scene:=aiImportFileExWithProperties( path,flags,Null,props )
  343. aiReleasePropertyStore( props )
  344. If Not scene
  345. Print "aiImportFile failed: path="+path
  346. Print "error="+aiGetErrorString()
  347. Return Null
  348. Endif
  349. Return scene
  350. End
  351. End