Blender -> Blitz (source inside)
Blitz3D Forums/Blitz3D Programming/Blender -> Blitz (source inside)
| ||
Hi again, This is my latest on the blender exporter. It comes in two parts; a python script that exports the current selected mesh from Blender. And a blitz program to load and display that mesh!. It does't really do much other then import a create a optimized blitz mesh (welding verts where possible). Support for vertex color and uv mapping is in there and works. Support for vertex normals should also work (untested). Textures that are used need to be copyed to the location that the blitz program is run from. I release this in the hope that someone will find it usefull!. My next step for this project should be a .b3d exporter (with some luck) :-) The Python script. #### [ Blender -> bb3d exporter ] #### """ Author : Stephen Greener (aka Shagwana) Purpose : Export selected mesh data to a file that can be converted into a .bb3d file """ ####[ Imports ]#### from Blender import * import struct ####[ Consts ]#### TRUE=1 FALSE=0 ####[ Varibles ]#### SaveFileName="C:\\BlitzExport.dat" # The file that the data will be saved too global OutputFile # File pointer to the above file while saving ####[ Procedures ]#### # Export this very polygon, and all related information! def ExportPolygon(f,Obj,ObjData,Face,v1,v2,v3): Vert1=Face.v[v1].index # Face vertex reference information... Vert2=Face.v[v2].index Vert3=Face.v[v3].index #Vertex information Coord1=ObjData.verts[Vert1].co # Coord information of this vertex Coord2=ObjData.verts[Vert2].co Coord3=ObjData.verts[Vert3].co Normal1=ObjData.verts[Vert1].no # Normal information Normal2=ObjData.verts[Vert2].no Normal3=ObjData.verts[Vert3].no #Vertex color information if Face.col: # Color information of the verts Color1=[Face.col[v1].r,Face.col[v1].g,Face.col[v1].b,Face.col[v1].a] Color2=[Face.col[v2].r,Face.col[v2].g,Face.col[v2].b,Face.col[v2].a] Color3=[Face.col[v3].r,Face.col[v3].g,Face.col[v3].b,Face.col[v3].a] bHasVC=TRUE else: Color1,Color2,Color3=[255,255,255,255],[255,255,255,255],[255,255,255,255] bHasVC=FALSE #UV information bHasUV=FALSE UV1,UV2,UV3=[0,1],[1,0],[1,1] # Default values for uv info UVName=[] # Default is no texture! if ObjData.hasFaceUV(): if Face.image: # Theres a texture to use! UVName=Face.image.name # Grabs the name UV1=Face.uv[v1] # Grab the uv coords! UV2=Face.uv[v2] UV3=Face.uv[v3] bHasUV=TRUE #Coord information... f.write(struct.pack("f",Coord1[0])) #X,Y,Z coords (reletive to the center).. f.write(struct.pack("f",Coord1[1])) f.write(struct.pack("f",Coord1[2])) f.write(struct.pack("f",Coord2[0])) #X,Y,Z coords (reletive to the center).. f.write(struct.pack("f",Coord2[1])) f.write(struct.pack("f",Coord2[2])) f.write(struct.pack("f",Coord3[0])) #X,Y,Z coords (reletive to the center).. f.write(struct.pack("f",Coord3[1])) f.write(struct.pack("f",Coord3[2])) #Normals... f.write(struct.pack("f",Normal1[0])) #X,Y,Z normal f.write(struct.pack("f",Normal1[1])) f.write(struct.pack("f",Normal1[2])) f.write(struct.pack("f",Normal2[0])) #X,Y,Z normal f.write(struct.pack("f",Normal2[1])) f.write(struct.pack("f",Normal2[2])) f.write(struct.pack("f",Normal3[0])) #X,Y,Z normal f.write(struct.pack("f",Normal3[1])) f.write(struct.pack("f",Normal3[2])) #Vertex color if bHasVC==TRUE: f.write(struct.pack("L",1)) #Yes, there is a set vertex color! f.write(struct.pack("f",Color1[0])) #Red f.write(struct.pack("f",Color1[1])) #Green f.write(struct.pack("f",Color1[2])) #Blue f.write(struct.pack("f",Color1[3])) #Alpha f.write(struct.pack("f",Color2[0])) #Red f.write(struct.pack("f",Color2[1])) #Green f.write(struct.pack("f",Color2[2])) #Blue f.write(struct.pack("f",Color2[3])) f.write(struct.pack("f",Color3[0])) #Red f.write(struct.pack("f",Color3[1])) #Green f.write(struct.pack("f",Color3[2])) #Blue f.write(struct.pack("f",Color3[3])) else: f.write(struct.pack("L",0)) #No vertex color set, use a default color! #Vertex uv texture mapping if bHasUV==TRUE: f.write(struct.pack("L",1)) #Yes there is UV mapping information f.write(UVName+chr(0)) #Name of texture that this polygon uses f.write(struct.pack("f",UV1[0])) #U f.write(struct.pack("f",UV1[1])) #V f.write(struct.pack("f",UV2[0])) #U f.write(struct.pack("f",UV2[1])) #V f.write(struct.pack("f",UV3[0])) #U f.write(struct.pack("f",UV3[1])) #V else: f.write(struct.pack("L",0)) #No uv mapping information # This will loop through the mesh and export all the polygons (3 vert and 4 verts) def ExportMesh(Obj,f): if Obj: f.write(Obj.name+chr(0)) # Save the name of this mesh first! iPolyCountPos=f.tell() f.write(struct.pack("L",0)) # How many polygons (dummy value) ObjData=Obj.getData() iPolygonCount=0 if ObjData: for face in ObjData.faces: Size=len(face.v) if Size==3: ExportPolygon(f,Obj,ObjData,face,0,1,2) iPolygonCount=iPolygonCount+1 elif Size==4: ExportPolygon(f,Obj,ObjData,face,0,1,2) ExportPolygon(f,Obj,ObjData,face,2,3,0) iPolygonCount=iPolygonCount+2 iCurrentPos=f.tell() f.seek(iPolyCountPos) f.write(struct.pack("L",iPolygonCount)) # How many polygons f.seek(iCurrentPos) ####[ Main program ]#### print "" print "Exporter started." #If the user has selected a object to work on... if Object.GetSelected()[0]: OutputFile=open(SaveFileName,'w+b') if OutputFile: OutputFile.write(struct.pack(">4s","B2BE")) #File header 'Blender To Blitz Exporter' ExportMesh(Object.GetSelected()[0],OutputFile) OutputFile.close() print "Exporter ended." The Blitz program. ; Coded by Stephen Greener (aka Shagwana) ; Load and display a blender exported mesh ; ;The location of the temp file to load the information from... Const INPUTFILE$="C:\BlitzExport.dat" ;The source file to build from ;Shared globals! Global sMeshName$="" ;Name od the loaded mesh! Global iMeshPolys=0 ;Imported basic polygons Type PolygonInfo Field fX1#,fY1#,fZ1# ;Coords Field fX2#,fY2#,fZ2# Field fX3#,fY3#,fZ3# Field fNX1#,fNY1#,fNZ1# ;Normals [not used yet!] Field fNX2#,fNY2#,fNZ2# Field fNX3#,fNY3#,fNZ3# Field bVCPresent ;Vertex colors present Field fR1#,fG1#,fB1#,fA1# ;[Alpha not used yet] Field fR2#,fG2#,fB2#,fA2# Field fR3#,fG3#,fB3#,fA3# Field bUVPresent ;Texture mapping present Field sTextureName$ Field fU1#,fV1# Field fU2#,fV2# Field fU3#,fV3# ;Processing varibles Field tTexture.TextureInfo ;Only used when Field tVert1.MasterVertexInfo ;When placed into the master vertex list, this reference's them! Field tVert2.MasterVertexInfo Field tVert3.MasterVertexInfo End Type ;The merged master vertex list for this mesh Type MasterVertexInfo ;This vertex information Field fXCoord#,fYCoord#,fZCoord# ;Coords Field fXNormal#,fYNormal#,fZNormal# ;Normals Field bVCPresent,fRed#,fGreen#,fBlue# ;Vertex colors Field bUVPresent,fU#,fV# ;Texture mapping Field tTexture.TextureInfo ;The surface used ;Used to show this vertex's Field iIndex End Type ;Shared texture id's - to make brushes out of Type TextureInfo Field sTextureName$ ;Name of this texture Field pSurface ;Pointer to this ones surface End Type tPolygon.PolygonInfo = Null tVertex.MasterVertexInfo = Null tTexture.TextureInfo = Null ;This will place the texture name into the list Function PlaceTexture.TextureInfo(sTextName$="") ;See if this texture matches an existing texture For tTexture.TextureInfo= Each TextureInfo If tTexture\sTextureName$=sTextName$ ;Matches Return tTexture.TextureInfo EndIf Next ;If here then need to append this texture tTexture.TextureInfo= New TextureInfo tTexture\sTextureName$=sTextName$ tTexture\pSurface=0 ;Build these in a moment Return tTexture.TextureInfo End Function ;Scan all polygons, return a surface that its going to be placed into Function BuildMasterTextureList(pMesh) ;Scan all textures - make them For tPolygon.PolygonInfo = Each PolygonInfo If tPolygon\bUVPresent=True ;Texture present tPolygon\tTexture.TextureInfo=PlaceTexture(tPolygon\sTextureName$) Else ;No texture, vc mesh! tPolygon\tTexture.TextureInfo=PlaceTexture() EndIf Next End Function ;This will load textures and create the surfaces required Function BuildSurfaces(pMesh) For tTexture.TextureInfo= Each TextureInfo If tTexture\sTextureName$<>"" ;Textures present on this surface pBrush=LoadBrush(tTexture\sTextureName$,49) tTexture\pSurface=CreateSurface(pMesh,pBrush) FreeBrush pBrush Else ;This is a non textured surface tTexture\pSurface=CreateSurface(pMesh) EndIf Next End Function ;Place a single vertex into the list (returns the verex pointer) Function PlaceVertex.MasterVertexInfo(fX#,fY#,fZ#,fNX#,fNY#,fNZ#,bVC,fR#,fG#,fB#,bUV,tTexture.TextureInfo,fU#,fV#) For tVertex.MasterVertexInfo = Each MasterVertexInfo ;Compare this vertex - if match, return its iID (postion) If (tVertex\fXCoord#=fX#) And (tVertex\fYCoord#=fY#) And (tVertex\fZCoord#=fZ#) And (tVertex\fXNormal#=fNX#) And (tVertex\fYNormal#=fNY#) And (tVertex\fZNormal#=fNZ#) ;Coords match bMatch=True If bVC=True If (tVertex\fRed#=fR#) And (tVertex\fGreen#=fG#) And (tVertex\fBlue#=fB#) bMatch=True Else bMatch=False EndIf EndIf If bMatch=True If tVertex\bVCPresent<>bVC ;One has the other dont bMatch=False EndIf EndIf If bMatch=True If bUV=True If (tVertex\tTexture\sTextureName$=tTexture\sTextureName$) And (tVertex\fU#=fU#) And (tVertex\fV#=fV#) bMatch=True Else bMatch=False EndIf EndIf EndIf If bMatch=True If tVertex\bUVPresent<>bUV bMatch=False EndIf EndIf If bMatch=True ;These verts match Return tVertex.MasterVertexInfo EndIf EndIf Next ;This appends a new vertex to the list tVertex.MasterVertexInfo = New MasterVertexInfo tVertex\fXCoord#=fX# tVertex\fYCoord#=fY# tVertex\fZCoord#=fZ# tVertex\bVCPresent=bVC tVertex\fRed#=fR# tVertex\fGreen#=fG# tVertex\fBlue#=fB# tVertex\bUVPresent=bUV tVertex\fU#=fU# tVertex\fV#=fV# tVertex\fXNormal#=fNX# ;Normals tVertex\fYNormal#=fNY# tVertex\fZNormal#=fNZ# tVertex\tTexture.TextureInfo=tTexture.TextureInfo Return tVertex.MasterVertexInfo End Function ;Scan the polygons, and make them refernce a single vertex list! Function BuildMasterVertexList() For tPolygon.PolygonInfo = Each PolygonInfo ;Merge these verts into the list tPolygon\tVert1.MasterVertexInfo=PlaceVertex(tPolygon\fX1#,tPolygon\fY1#,tPolygon\fZ1#,tPolygon\fNX1#,tPolygon\fNY1#,tPolygon\fNZ1#,tPolygon\bVCPresent,tPolygon\fR1#,tPolygon\fG1#,tPolygon\fB1#,tPolygon\bUVPresent,tPolygon\tTexture.TextureInfo,tPolygon\fU1#,tPolygon\fV1#) tPolygon\tVert2.MasterVertexInfo=PlaceVertex(tPolygon\fX2#,tPolygon\fY2#,tPolygon\fZ2#,tPolygon\fNX2#,tPolygon\fNY2#,tPolygon\fNZ2#,tPolygon\bVCPresent,tPolygon\fR2#,tPolygon\fG2#,tPolygon\fB2#,tPolygon\bUVPresent,tPolygon\tTexture.TextureInfo,tPolygon\fU2#,tPolygon\fV2#) tPolygon\tVert3.MasterVertexInfo=PlaceVertex(tPolygon\fX3#,tPolygon\fY3#,tPolygon\fZ3#,tPolygon\fNX3#,tPolygon\fNY3#,tPolygon\fNZ3#,tPolygon\bVCPresent,tPolygon\fR3#,tPolygon\fG3#,tPolygon\fB3#,tPolygon\bUVPresent,tPolygon\tTexture.TextureInfo,tPolygon\fU3#,tPolygon\fV3#) Next End Function ;This will place the vers in the correct surfaces! Function MakeObj(pMesh) ;Place verts first For tVertex.MasterVertexInfo = Each MasterVertexInfo tVertex\iIndex=AddVertex(tVertex\tTexture\pSurface,tVertex\fXCoord#,tVertex\fYCoord#,tVertex\fZCoord#,tVertex\fU#,tVertex\fV#) VertexNormal tVertex\tTexture\pSurface,tVertex\iIndex,tVertex\fXNormal#,tVertex\fYNormal#,tVertex\fZNormal# If tVertex\bVCPresent=True VertexColor tVertex\tTexture\pSurface,tVertex\iIndex,tVertex\fRed#,tVertex\fGreen#,tVertex\fBlue# EndIf Next ;Now add in the triangles For tPolygon.PolygonInfo = Each PolygonInfo AddTriangle tPolygon\tTexture\pSurface,tPolygon\tVert1\iIndex,tPolygon\tVert2\iIndex,tPolygon\tVert3\iIndex Next End Function ;This will import the selected file, and return a optimized blitz mesh (some calculations are done) Function ImportMesh(BlenderFilename$) pMesh=0 If LoadPolys(BlenderFilename$)=True pMesh=CreateMesh() ;Polygons loaded into a temp format BuildMasterTextureList(pMesh) ;<sort textures into order> BuildSurfaces(pMesh) BuildMasterVertexList() MakeObj(pMesh) EntityFX pMesh,2 ScaleMesh pMesh,0.2,0.2,0.2 RotateMesh pMesh,-135,0,0 EndIf Return pMesh End Function ;Read from stream null terminated string.... Function ReadNullTerminatedString$(pF) Msg$="" Repeat b=ReadByte(pF) If b<>0 Msg$=Msg$+Chr(b) EndIf Until b=0 Return Msg$ End Function ;Read from stream 4byte string (file headers) Function Read4CharString$(pF) Msg$=Chr(ReadByte(pF))+Chr(ReadByte(pF))+Chr(ReadByte(pF))+Chr(ReadByte(pF)) Return Msg$ End Function ;This imports the needed information that was exported from blender Function LoadPolys(Filename$) bLoaded=False pF=ReadFile(Filename$) If pF<>0 If Read4CharString$(pF)="B2BE" ;Blender 2 Blitz Exporter! sMeshName$=ReadNullTerminatedString$(pF) ;Name of the mesh bDone=False iMeshPolys=ReadInt(pF) ;Number of polygons in this file! For p=0 To iMeshPolys bLoaded=True ;Read this polygon in from the file tPolygon.PolygonInfo = New PolygonInfo ;Load coords for the polys verts tPolygon\fX1#=ReadFloat(pF) tPolygon\fY1#=ReadFloat(pF) tPolygon\fZ1#=ReadFloat(pF) tPolygon\fX2#=ReadFloat(pF) tPolygon\fY2#=ReadFloat(pF) tPolygon\fZ2#=ReadFloat(pF) tPolygon\fX3#=ReadFloat(pF) tPolygon\fY3#=ReadFloat(pF) tPolygon\fZ3#=ReadFloat(pF) ;Load the normals, per poly verts tPolygon\fNX1#=ReadFloat(pF) tPolygon\fNY1#=ReadFloat(pF) tPolygon\fNZ1#=ReadFloat(pF) tPolygon\fNX2#=ReadFloat(pF) tPolygon\fNY2#=ReadFloat(pF) tPolygon\fNZ2#=ReadFloat(pF) tPolygon\fNX3#=ReadFloat(pF) tPolygon\fNY3#=ReadFloat(pF) tPolygon\fNZ3#=ReadFloat(pF) ;Load in the vertex colors If ReadInt(pF)=1 tPolygon\bVCPresent=True tPolygon\fR1#=ReadFloat(pF) tPolygon\fG1#=ReadFloat(pF) tPolygon\fB1#=ReadFloat(pF) tPolygon\fA1#=ReadFloat(pF) tPolygon\fR2#=ReadFloat(pF) tPolygon\fG2#=ReadFloat(pF) tPolygon\fB2#=ReadFloat(pF) tPolygon\fA2#=ReadFloat(pF) tPolygon\fR3#=ReadFloat(pF) tPolygon\fG3#=ReadFloat(pF) tPolygon\fB3#=ReadFloat(pF) tPolygon\fA3#=ReadFloat(pF) Else tPolygon\bVCPresent=False EndIf ;Load in texture mapping If ReadInt(pF)=1 tPolygon\bUVPresent=True tPolygon\sTextureName$=ReadNullTerminatedString$(pF) tPolygon\fU1#=ReadFloat(pF) tPolygon\fV1#=ReadFloat(pF) tPolygon\fU2#=ReadFloat(pF) tPolygon\fV2#=ReadFloat(pF) tPolygon\fU3#=ReadFloat(pF) tPolygon\fV3#=ReadFloat(pF) Else tPolygon\bUVPresent=False tPolygon\sTextureName$="" EndIf Next EndIf CloseFile(pF) EndIf Return bLoaded End Function ;Count all verts in a given mesh Function CountVertsInMesh(pMesh) S=CountSurfaces(pMesh) T=0 For n=1 To S T=T+CountVertices(GetSurface(pMesh,n)) Next Return T End Function ;The test application... Graphics3D 800,600,32,0 SetBuffer BackBuffer() pCamera=CreateCamera() ;Our eye pLight=CreateLight() ;A light! pObj=ImportMesh(INPUTFILE$) ;Load the mesh in If pObj<>0 Then PositionEntity pObj,0,0,5 ;Temp fXView#=0.0 fYView#=0.0 fZView#=0.0 CameraClsColor pCamera,60,70,90 While Not KeyDown( 1 ) ;Simple viewing of the created mesh using the mouse If KeyDown(75) ;num_4 fXView#=fXView#-5 If fXView#<-50 Then fXView#=-50 EndIf If KeyDown(77) ;num_6 fXView#=fXView#+5 If fXView#>50 Then fXView#=50 EndIf If KeyDown(72) ;num_8 fYView#=fYView#-5 If fYView#<-50 Then fYView#=-50 EndIf If KeyDown(80) ;num_2 fYView#=fYView#+5 If fYView#>50 Then fYView#=50 EndIf fXView#=fXView#*0.9 fYView#=fYView#*0.9 fZView#=fZView#*0.9 If pObj<>0 Then TurnEntity pObj,0.01*fYView#,0.01*fXView#,0.01*fZView# ;Update the display RenderWorld Color 0,0,255 Text 0,0," Mesh: "+sMeshName$+" Polys in file: "+iMeshPolys Text 0,16," Tris: "+TrisRendered()+" Verts:"+CountVertsInMesh(pObj) n=0 For tTexture.TextureInfo= Each TextureInfo n=n+1 If tTexture\sTextureName$="" Text 100,((16*n)+32),n+" -> [vertex color surface]" Else Text 100,((16*n)+32),n+" -> "+tTexture\sTextureName$ EndIf Next Flip Cls Wend End |
| ||
Cool :) thx. I wil give it a try ; |
| ||
Hey Cool! Amazing! I dream to do in Blender Editor all the things, and have then a full ODE (dynamic) scene :))) Remember to consider to add (in a future) such an exporting option! (maybe in format of .bb code) cya! |
| ||
*bump* If you have a working export path from blender to blitz, why not give mark a shout, to host it on the sdk page... |
| ||
I am in your debt sir. |
| ||
Good stuff, I've been using the .X exporter up to now. I don't suppose theres any chance of getting this to work with vertex animations/armatures is there? |
| ||
If you have a working export path from blender to blitz Its not ready yet, i hope to have a b3d version working one day - then, that day will be the day :) I don't suppose theres any chance of getting this to work with vertex animations/armatures is there? Problem with that is that Blender in its current state dose't expose the bones data to python - so theres no way o export it. I will look into it further, hopefully there is a way around it :) |
| ||
>> Problem with that is that Blender in its current state dose't expose the bones data to python - so theres no way o export it. I will look into it further, hopefully there is a way around it :) Thats a bit fatal. A way round it (nasty way) could be to expect the user to create a set of empties, where an empty exists for each bone. Then read the orientations etc of those. I could of course try adding a .B3D export directly into the source now . . . |
| ||
Update time to this old topic... www.Blender.org has just released a new version of Blender (v2.28+) that gives scripters access to bone data!! (with other new features for pyhton too). So When I get back from work later today, Its gona be time to look at the Blender exporter again :). |