assimp.monkey2 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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 tp:=aimesh.mTextureCoords[0]
  115. For Local i:=0 Until vertices.Length
  116. vertices[i].position=New Vec3f( vp[i].x,vp[i].y,vp[i].z )
  117. If np
  118. vertices[i].normal=New Vec3f( np[i].x,np[i].y,np[i].z )
  119. Endif
  120. If cp
  121. Local color:=cp[i]
  122. Local a:=color.a * 255.0
  123. vertices[i].color=UInt(a) Shl 24 | UInt(color.b*a) Shl 16 | UInt(color.g*a) Shl 8 | UInt(color.r*a)
  124. Endif
  125. If tp
  126. vertices[i].texCoord0=New Vec2f( tp[i].x,tp[i].y )
  127. Endif
  128. Next
  129. Local indices:=New UInt[ aimesh.mNumFaces*3 ]
  130. Local fp:=aimesh.mFaces,v0:=mesh.NumVertices
  131. For Local i:=0 Until aimesh.mNumFaces
  132. If fp[i].mNumIndices<>3
  133. Print "not a triangle! "+fp[i].mNumIndices
  134. Endif
  135. indices[i*3+0]=fp[i].mIndices[0]+v0
  136. indices[i*3+1]=fp[i].mIndices[1]+v0
  137. indices[i*3+2]=fp[i].mIndices[2]+v0
  138. Next
  139. If model And boned And aimesh.mNumBones LoadBones( aimesh,model,vertices )
  140. mesh.AddVertices( vertices )
  141. mesh.AddTriangles( indices,mesh.NumMaterials-1 )
  142. End
  143. Method LoadMaterial:Material( aimesh:aiMesh,boned:bool )
  144. Local index:=aimesh.mMaterialIndex
  145. If index<_materials.Length And _materials[index] Return _materials[index]
  146. If index>=_materials.Length _materials.Resize( index+1 )
  147. _materials[index]=LoadMaterial( _scene.mMaterials[index],boned )
  148. Return _materials[index]
  149. End
  150. Method LoadMaterial:Material( aimaterial:aiMaterial,boned:Bool )
  151. Local ainame:aiString,name:String
  152. aiGetMaterialString( aimaterial,AI_MATKEY_NAME,0,0,Varptr ainame )
  153. name=ainame.data
  154. Local diffuseTexture:Texture=Null
  155. Local aipath:aiString,path:String
  156. aiGetMaterialTexture( aimaterial,aiTextureType_DIFFUSE,0,Varptr aipath )
  157. path=aipath.data
  158. If path
  159. path=_dir+StripDir( path )
  160. diffuseTexture=Texture.Load( path,TextureFlags.FilterMipmap|TextureFlags.WrapST )
  161. Endif
  162. Local diffuseColor:Color=Color.White
  163. Local aicolor:aiColor4D
  164. aiGetMaterialColor( aimaterial,AI_MATKEY_COLOR_DIFFUSE,0,0,Varptr aicolor )
  165. diffuseColor=New Color( Pow( aicolor.r,2.2 ),Pow( aicolor.g,2.2 ),Pow( aicolor.b,2.2 ),aicolor.a )
  166. Local material:=New PbrMaterial
  167. material.Boned=boned
  168. material.Name=name
  169. If diffuseTexture material.ColorTexture=diffuseTexture
  170. material.ColorFactor=diffuseColor
  171. Return material
  172. End
  173. Method EnumEntityIds( node:aiNode )
  174. _entityIds[ node.mName.data ]=_entityIds.Count()
  175. For Local i:=0 Until node.mNumChildren
  176. EnumEntityIds( node.mChildren[i] )
  177. Next
  178. End
  179. Method CreateNodes( node:aiNode,parent:Model )
  180. Local model:=New Model( parent )
  181. model.Name=node.mName.data
  182. model.LocalMatrix=Cast<AffineMat4f>( node.mTransformation )
  183. _nodes[ model.Name ]=model
  184. _entityIds[ model.Name ]=_entities.Length
  185. _entities.Push( model )
  186. For Local i:=0 Until node.mNumChildren
  187. CreateNodes( node.mChildren[i],model )
  188. Next
  189. End
  190. Method LoadNodes( node:aiNode )
  191. Local model:=Cast<Model>( _nodes[ node.mName.data ] )
  192. Local mesh:=New Mesh
  193. Local materials:=New Stack<Material>
  194. For Local i:=0 Until node.mNumMeshes
  195. Local aimesh:=_scene.mMeshes[ node.mMeshes[i] ]
  196. mesh.AddMaterials( 1 )
  197. Local boned:=aimesh.mNumBones>0
  198. LoadMesh( aimesh,mesh,model,boned )
  199. materials.Push( LoadMaterial( aimesh,boned ) )
  200. Next
  201. If materials.Length
  202. mesh.UpdateTangents()
  203. model.Mesh=mesh
  204. model.Materials=materials.ToArray()
  205. Endif
  206. For Local i:=0 Until node.mNumChildren
  207. LoadNodes( node.mChildren[i] )
  208. Next
  209. End
  210. Method LoadAnimationChannel:AnimationChannel( aichan:aiNodeAnim )
  211. Local posKeys:=New PositionKey[ aichan.mNumPositionKeys ]
  212. For Local i:=0 Until posKeys.Length
  213. Local aikey:=aichan.mPositionKeys[i]
  214. posKeys[i]=New PositionKey( aikey.mTime,aikey.mValue )
  215. Next
  216. Local rotKeys:=New RotationKey[ aichan.mNumRotationKeys ]
  217. For Local i:=0 Until rotKeys.Length
  218. Local aikey:=aichan.mRotationKeys[i]
  219. rotKeys[i]=New RotationKey( aikey.mTime,aikey.mValue )
  220. Next
  221. Local sclKeys:=New ScaleKey[ aichan.mNumScalingKeys ]
  222. For Local i:=0 Until sclKeys.Length
  223. Local aikey:=aichan.mScalingKeys[i]
  224. sclKeys[i]=New ScaleKey( aikey.mTime,aikey.mValue )
  225. Next
  226. Return New AnimationChannel( posKeys,rotKeys,sclKeys )
  227. End
  228. Method LoadAnimation:Animation( aianim:aiAnimation )
  229. ' Print "_entities.Length="+_entities.Length
  230. ' Print "_entityIds.Count="+_entityIds.Count()
  231. ' Print "mNumChannels="+aianim.mNumChannels
  232. Local channels:=New AnimationChannel[ _entityIds.Count() ]
  233. For Local i:=0 Until aianim.mNumChannels
  234. Local aichan:=aianim.mChannels[i]
  235. Local id:=_entityIds[ aichan.mNodeName.data ]
  236. Local channel:=LoadAnimationChannel( aichan )
  237. channels[id]=channel
  238. ' Print "channel "+id+", numposkeys="+channel.PositionKeys.Length+", numrotkeys="+channel.RotationKeys.Length+", numsclkeys="+channel.ScaleKeys.Length
  239. Next
  240. ' Print "duration="+aianim.mDuration+", mTicksPerSecond="+aianim.mTicksPerSecond
  241. Local animation:=New Animation( aianim.mName.data,channels,aianim.mDuration,aianim.mTicksPerSecond,AnimationMode.Looping )
  242. Return animation
  243. End
  244. Method LoadAnimator:Animator( entity:Entity )
  245. ' Print "mNumAnimations="+_scene.mNumAnimations
  246. If Not _scene.mNumAnimations Return Null
  247. Local animations:=New Animation[_scene.mNumAnimations]
  248. For Local i:=0 Until _scene.mNumAnimations
  249. animations[i]=LoadAnimation( _scene.mAnimations[i] )
  250. Next
  251. Local animator:=New Animator( entity )
  252. animator.Skeleton=_entities.ToArray()
  253. animator.Animations.AddAll( animations )
  254. Return animator
  255. End
  256. End
  257. Public
  258. #rem monkeydoc @hidden
  259. #End
  260. Class AssimpMojo3dLoader Extends Mojo3dLoader
  261. Const Instance:=New AssimpMojo3dLoader
  262. Method LoadMesh:Mesh( path:String ) Override
  263. Local flags:UInt=0
  264. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  265. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  266. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  267. flags|=aiProcess_GenSmoothNormals |aiProcess_FixInfacingNormals | aiProcess_Triangulate
  268. flags|=aiProcess_PreTransformVertices
  269. flags|=aiProcess_FindInvalidData
  270. flags|=aiProcess_OptimizeMeshes
  271. Local scene:=LoadScene( path,flags )
  272. If Not scene Return Null
  273. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  274. Local mesh:=loader.LoadMesh()
  275. Return mesh
  276. End
  277. Method LoadModel:Model( path:String ) Override
  278. Local flags:UInt=0
  279. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  280. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  281. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  282. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  283. flags|=aiProcess_GenSmoothNormals |aiProcess_Triangulate
  284. flags|=aiProcess_PreTransformVertices
  285. flags|=aiProcess_FindInvalidData
  286. flags|=aiProcess_OptimizeMeshes
  287. Local scene:=LoadScene( path,flags )
  288. If Not scene Return Null
  289. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  290. Local model:=loader.LoadModel()
  291. Return model
  292. End
  293. Method LoadBonedModel:Model( path:String ) Override
  294. Local flags:UInt=0
  295. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  296. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  297. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  298. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  299. flags|=aiProcess_GenSmoothNormals |aiProcess_Triangulate
  300. ' flags|=aiProcess_SplitByBoneCount
  301. ' flags|=aiProcess_LimitBoneWeights
  302. ' flags|=aiProcess_FindInvalidData
  303. ' flags|=aiProcess_OptimizeMeshes
  304. ' flags|=aiProcess_OptimizeGraph 'fails quite spectacularly!
  305. Local scene:=LoadScene( path,flags )
  306. If Not scene Return Null
  307. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  308. Local model:=loader.LoadBonedModel()
  309. Return model
  310. End
  311. Method LoadAnimation:Animation( path:String ) Override
  312. Local flags:UInt=0
  313. flags|=aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
  314. 'flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_SortByPType
  315. flags|=aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType
  316. ' flags|=aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_Triangulate
  317. flags|=aiProcess_GenSmoothNormals |aiProcess_Triangulate
  318. ' flags|=aiProcess_SplitByBoneCount
  319. flags|=aiProcess_LimitBoneWeights
  320. flags|=aiProcess_FindInvalidData
  321. flags|=aiProcess_OptimizeMeshes
  322. ' flags|=aiProcess_OptimizeGraph 'fails quite spectacularly!
  323. Local scene:=LoadScene( path,flags )
  324. If Not scene Return Null
  325. Local loader:=New AssimpLoader( scene,ExtractDir( path ) )
  326. Local animation:=loader.LoadAnimation()
  327. Return animation
  328. End
  329. Private
  330. Function LoadScene:aiScene( path:String,flags:UInt )
  331. Local props:=aiCreatePropertyStore()
  332. aiSetImportPropertyInteger( props,AI_CONFIG_PP_SBP_REMOVE,aiPrimitiveType_POINT | aiPrimitiveType_LINE )
  333. aiSetImportPropertyInteger( props,AI_CONFIG_PP_FD_REMOVE,1 )
  334. aiSetImportPropertyInteger( props,AI_CONFIG_PP_SBBC_MAX_BONES,64 )
  335. path=RealPath( path )
  336. Local scene:=aiImportFileExWithProperties( path,flags,Null,props )
  337. aiReleasePropertyStore( props )
  338. If Not scene
  339. Print "aiImportFile failed: path="+path
  340. Print "error="+aiGetErrorString()
  341. Return Null
  342. Endif
  343. Return scene
  344. End
  345. End