B3D File Format
Blitz3D Forums/Blitz3D Programming/B3D File Format
| ||
Hi,hope someone can help, I'm a bit of a clutz with file formats. I'm trying to bring together JFK's SaveB3D code and sswift's Calculate Normals code from the code archives. I've been using both of these seperatly for quite a while and they work very well...many thanks to you both for the code. However, what I would like to do is to load the mesh...calculate the normals then save the mesh with the new normals. Mainly so I can then load the meshes into other Blitz related apps with the correct normals. I've got things working OK but when the file is saved, the new normals aren't. I've checked out the B3D specs and think I need to be looking at the Verts part of the code in the WriteMesh(Mesh) function. Seems I need to set the first Int flag to 1 ...but when I do this my system just hangs after I reach the "Press any key to save this mesh" part. I've also tried adding this to the to the WriteMesh(Mesh) function...do I need to do this? b3dWriteFloat( VertexNX( surf,j ) ) b3dWriteFloat( VertexNY( surf,j ) ) b3dWriteFloat( VertexNZ( surf,j ) ) However my system still just hangs. I've found an endless number of ways of how NOT to do it but can't seem to find the right way. LOL If some kind person could point me in the right direction it would be much appreciated....Thanks. ;Thanks to JFK and sswift for all the code Graphics3D 640,480,32,2 SetBuffer BackBuffer() Include "b3dfile.bb" ; this file can be found here: http://www.blitzbasic.com/sdkspecs/sdkspecs/b3dfile_utils.zip Dim Face_NX#(32768) Dim Face_NY#(32768) Dim Face_NZ#(32768) Dim Vertex_ConnectedTris(32768) Dim Vertex_TriList(32768, 32) Global Mesh Global MeshName$ cam=CreateCamera() TranslateEntity cam,0,0,-10 light=CreateLight(2) AmbientLight 0,0,0 MeshName$="Whatever.x" ; Mesh to save... (one that is using textures) Mesh=LoadMesh(MeshName$) ;Load the mesh Calculate_Normals(Mesh) ;Calculate the new normals For n=1 To Len(meshname$) ;Drop the file extension mi$=Mid$(meshname$,n,1) If mi$="." Then length=n-1 Next For n=1 To length ;Load new mesh name into a$ a$ = a$ + Mid(meshname$,n,1) Next ; BTW: you should run this from inside the folder where the Mesh resides, unless you edit the ; Part labeled by "<<<<<<<<<<<<" Global c_surfs=CountSurfaces(mesh) Global name$ Print "Mesh "+Meshname$+" has "+ c_surfs+" Surfaces, using the following textures:" Dim c_surf(c_surfs) Dim c_brush(c_surfs) Dim c_tex(c_surfs) Dim c_tex_name$(c_surfs) ; track down used textures (thanks Mark!) For i=1 To c_surfs c_surf(i)= GetSurface(mesh,i) c_brush(i)=GetSurfaceBrush( c_surf(i) ) c_tex(i)=GetBrushTexture( c_brush(i) ) c_tex_name$(i)=Lower$(TextureName$( c_tex(i))) ; Full (!) Texture Path curdir$=Lower$(CurrentDir$()) c_tex_name$(i)= Replace$(c_tex_name$(i),curdir$,"") ;<<<<<<<<<<<<<<<<<<< Print c_tex_name$(i) If c_tex_name$(i)="" Then Print "Error: Surface No."+i+" has no Texture" If FileType(c_tex_name$(i))<>1 Then Print "Warning: Surface No."+i+" uses nonexistant Texture ("+c_tex_name$(i)+")." Next Print "Press any key to save this Mesh as a .b3d File" WaitKey() ; end WriteBB3D( a$+".b3d",mesh ) For i=1 To c_surfs FreeBrush c_brush(i); release memory FreeTexture c_tex(i) Next ; test if it worked... FreeEntity mesh mesh2=LoadMesh(a$+".b3d") While Not KeyDown(1) TurnEntity mesh2,1,2,3 RenderWorld() Text 0,0,a$+".b3d" Flip Wend ClearWorld End Function WriteBB3D( f_name$,mesh ) file=WriteFile( f_name$ ) b3dSetFile( file ) b3dBeginChunk( "BB3D" ) b3dWriteInt( 1 ) ;version b3dBeginChunk( "TEXS" ) ; list all textures used by the mesh For i=1 To c_surfs b3dWriteString( c_tex_name$(i) ) ;texture file b3dWriteInt( 1 ) ;flags b3dWriteInt( 2 ) ;blend b3dWriteFloat( 0 ) ;x in tex 0 (hu?) b3dWriteFloat( 0 ) ;y in tex 0 b3dWriteFloat( 1 ) ;x scale 1 b3dWriteFloat( 1 ) ;y scale 1 b3dWriteFloat( 0 ) ;rotation 0 Next b3dEndChunk() ;end of TEXS chunk For i=1 To c_surfs DropType$=Right$(c_tex_name$(i),4) c_tex_name$(i)=Replace$(c_tex_name$(i),DropType$,"") ;Drop the file type for materials b3dBeginChunk( "BRUS" ) ; describe all brushes used by the mesh b3dWriteInt( 1 ) ;number of textures per brush ; (eg 2 with lightmap) ;b3dWriteString( "brush"+(i-1) ) ;brushname b3dWriteString(c_tex_name$(i) ) b3dWriteFloat( 1 ) ;red b3dWriteFloat( 1 ) ;green b3dWriteFloat( 1 ) ;blue b3dWriteFloat( 1 ) ;alpha b3dWriteFloat( 0 ) ;shininess b3dWriteInt( 1 ) ;blendmode b3dWriteInt( 0 ) ;FX b3dWriteInt( i-1 ) ;used texture index ; b3dWriteInt( ? ) ;additional texture index (eg lightmap), but here we only use 1 (see above) b3dEndChunk() ;end of BRUS chunk Next b3dBeginChunk( "NODE" ) b3dWriteString( "entity_name_here!" ) b3dWriteFloat( 0 ) ;x_pos b3dWriteFloat( 0 ) ;y_pos b3dWriteFloat( 0 ) ;z_pos b3dWriteFloat( 1 ) ;x_scale b3dWriteFloat( 1 ) ;y_scale b3dWriteFloat( 1 ) ;z_scale b3dWriteFloat( 1 ) ;rot_w b3dWriteFloat( 0 ) ;rot_x b3dWriteFloat( 0 ) ;rot_y b3dWriteFloat( 0 ) ;rot_z WriteMESH( mesh ) b3dEndChunk() ;end of NODE chunk b3dEndChunk() ;end of BB3D chunk CloseFile file End Function Function WriteMESH( mesh ) n_surfs=CountSurfaces( mesh ) b3dBeginChunk( "MESH" ) b3dWriteInt( -1 ) ;no 'entity' brush -1 b3dBeginChunk( "VRTS" ) b3dWriteInt( 0 ) ;flags - 0=no normal/color b3dWriteInt( 1 ) ;number of tex_coord sets (eg: 2 with lightmap) b3dWriteInt( 2 ) ;coords per set (u,v,w?) 2 with uv, 3 with uvw For k=1 To n_surfs surf=GetSurface( mesh,k ) n_verts=CountVertices( surf )-1 For j=0 To n_verts b3dWriteFloat( VertexX( surf,j ) ) b3dWriteFloat( VertexY( surf,j ) ) b3dWriteFloat( VertexZ( surf,j ) ) b3dWriteFloat( VertexU#( surf,j,0 ) ) b3dWriteFloat( VertexV#( surf,j,0 ) ) ; b3dWriteFloat( VertexW#( surf,j,0 ) ) ;; b3dWriteFloat( VertexU#( surf,j,1 ) ) ; lightmap uv ;; b3dWriteFloat( VertexV#( surf,j,1 ) ) ; lightmap uv ; b3dWriteFloat( VertexW#( surf,j,1 ) ) Next Next b3dEndChunk() ;end of VRTS chunk first_vert=0 For k=1 To n_surfs surf=GetSurface( mesh,k ) n_tris=CountTriangles( surf )-1 b3dBeginChunk( "TRIS" ) b3dWriteInt( k-1 ) ;brush for these triangles (surf -1 !!!) For j=0 To n_tris b3dWriteInt( first_vert+TriangleVertex( surf,j,0 ) ) b3dWriteInt( first_vert+TriangleVertex( surf,j,1 ) ) b3dWriteInt( first_vert+TriangleVertex( surf,j,2 ) ) Next b3dEndChunk() ;end of TRIS chunk first_vert=first_vert+CountVertices( surf ) Next b3dEndChunk() ;end of MESH chunk End Function Function getextension$(filename$) ; Returns the extension minus the . lastdir = 1 For i=1 To Len(filename$) If Mid$(filename$,i,1) = "." Then Lastdir = i Next If Lastdir > 1 Then Lastdir = Lastdir + 1 For i=Lastdir To Len(filename$) a$ = a$ + Mid(filename$,i,1) Next Return a$ End Function ; ------------------------------------------------------------------------------------------------------------------- ; This function calculates and sets the normals for a mesh. ; ; Should probably update this so that it can recursively loop through all of an entities children as well. ; ------------------------------------------------------------------------------------------------------------------- Function Calculate_Normals(Mesh) ; Loop through all surfaces of the mesh. Surfaces = CountSurfaces(Mesh) For LOOP_Surface = 1 To Surfaces Surface_Handle = GetSurface(Mesh, LOOP_Surface) ; Reset the number of connected polygons for each vertex. For LoopV = 0 To 32767 Vertex_ConnectedTris(LoopV) = 0 Next ; Loop through all triangles in this surface of the mesh. Tris = CountTriangles(Surface_Handle) For LOOP_Tris = 0 To Tris-1 ; Get the vertices that make up this triangle. Vertex_0 = TriangleVertex(Surface_Handle, LOOP_Tris, 0) Vertex_1 = TriangleVertex(Surface_Handle, LOOP_Tris, 1) Vertex_2 = TriangleVertex(Surface_Handle, LOOP_Tris, 2) ; Adjust the number of triangles each vertex is connected to and ; store this triangle in each vertex's list of triangles it is connected to. ConnectedTris = Vertex_ConnectedTris(Vertex_0) Vertex_TriList(Vertex_0, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_0) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_1) Vertex_TriList(Vertex_1, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_1) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_2) Vertex_TriList(Vertex_2, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_2) = ConnectedTris + 1 ; Calculate the normal for this face. ; Get the corners of this face: Ax# = VertexX#(Surface_Handle, Vertex_0) Ay# = VertexY#(Surface_Handle, Vertex_0) Az# = VertexZ#(Surface_Handle, Vertex_0) Bx# = VertexX#(Surface_Handle, Vertex_1) By# = VertexY#(Surface_Handle, Vertex_1) Bz# = VertexZ#(Surface_Handle, Vertex_1) Cx# = VertexX#(Surface_Handle, Vertex_2) Cy# = VertexY#(Surface_Handle, Vertex_2) Cz# = VertexZ#(Surface_Handle, Vertex_2) ; Triangle 1 ; Get the vectors for two edges of the triangle. Px# = Ax#-Bx# Py# = Ay#-By# Pz# = Az#-Bz# Qx# = Bx#-Cx# Qy# = By#-Cy# Qz# = Bz#-Cz# ; Compute their cross product. Nx# = Py#*Qz# - Pz#*Qy# Ny# = Pz#*Qx# - Px#*Qz# Nz# = Px#*Qy# - Py#*Qx# ; Store the face normal. Face_NX#(LOOP_Tris) = Nx# Face_NY#(LOOP_Tris) = Ny# Face_NZ#(LOOP_Tris) = Nz# Next ; Now that all the face normals for this surface have been calculated, calculate the vertex normals. Vertices = CountVertices(Surface_Handle) For LOOP_Vertices = 0 To Vertices-1 ; Reset this normal. Nx# = 0 Ny# = 0 Nz# = 0 ; Add the normals of all polygons which are connected to this vertex. Polys = Vertex_ConnectedTris(LOOP_Vertices) For LOOP_Polys = 0 To Polys-1 ThisPoly = Vertex_TriList(LOOP_Vertices, LOOP_Polys) Nx# = Nx# + Face_NX#(ThisPoly) Ny# = Ny# + Face_NY#(ThisPoly) Nz# = Nz# + Face_NZ#(ThisPoly) Next ; Normalize the new vertex normal. ; (Normalizing is scaling the vertex normal down so that it's length = 1) Nl# = Sqr(Nx#^2 + Ny#^2 + Nz#^2) ; Avoid a divide by zero error if by some freak accident, the vectors add up to 0. ; If Nl# = 0 Then Nl# = 0.1 Nx# = Nx# / Nl# Ny# = Ny# / Nl# Nz# = Nz# / Nl# ; Set the vertex normal. VertexNormal Surface_Handle, LOOP_Vertices, Nx#, Ny#, Nz# ;VertexColor Surface_Handle, LOOP_Vertices, polys*127, polys*127, polys*127 Next Next End Function |
| ||
As it is this code works but doesn't save the new normals. |
| ||
You might want a look at this: http://www.zen54709.zen.co.uk/b3dformat.htm |
| ||
I've also tried adding this to the to the WriteMesh(Mesh) function...do I need to do this? b3dWriteFloat( VertexNX( surf,j ) ) b3dWriteFloat( VertexNY( surf,j ) ) b3dWriteFloat( VertexNZ( surf,j ) ) Yes you need to write the new normal values to the file as well. First of set the Vertex Flag to the value of 1. The value 0 that you are setting means that you are storing vertex positions only. You need to add 1 to this value for vertex normals and add another 2 for vertex color. e.g 0=vertex positions only 1=positions+normals 2=positions+colour 3=positions+normals+colour You need to set the vertex flag value to 1 and then write the vertex normal values after the position values. b3dBeginChunk( "VRTS" ) b3dWriteInt( 1 ) ;flags - 0=position only, 1= position+normals b3dWriteInt( 1 ) ;number of tex_coord sets (eg: 2 with lightmap) b3dWriteInt( 2 ) ;coords per set (u,v,w?) 2 with uv, 3 with uvw For k=1 To n_surfs surf=GetSurface( mesh,k ) n_verts=CountVertices( surf )-1 For j=0 To n_verts b3dWriteFloat( VertexX( surf,j ) ) b3dWriteFloat( VertexY( surf,j ) ) b3dWriteFloat( VertexZ( surf,j ) ) b3dWriteFloat( VertexNX( surf,j ) ) b3dWriteFloat( VertexNY( surf,j ) ) b3dWriteFloat( VertexNZ( surf,j ) ) b3dWriteFloat( VertexU#( surf,j,0 ) ) b3dWriteFloat( VertexV#( surf,j,0 ) ) ; b3dWriteFloat( VertexW#( surf,j,0 ) ) ;; b3dWriteFloat( VertexU#( surf,j,1 ) ) ; lightmap uv ;; b3dWriteFloat( VertexV#( surf,j,1 ) ) ; lightmap uv ; b3dWriteFloat( VertexW#( surf,j,1 ) ) Next Next b3dEndChunk() ;end of VRTS chunk |
| ||
Beaker....many thanks for the link. I haven't seen this before, looks very interesting, should learn a bit more with this. Smiff...great stuff...that works just fine, brilliant. I can move forward a bit now, many thanks. It's strange you should answere this post, I just downloaded the demo for Pacemaker a couple of days ago. :) |