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 :). |