PhysX 3.2中RAW格式文件的解析
在PhysX 3.2中 ,Sample结合了D3D9来做显示。
在SampleVehicle中,使用了raw格式的文件来存储车辆模型和天空。
最初的时候,我以为这个raw格式就是网上说的那个原生照片格式,但是后来跟进到程序里面发现这个raw格式包含的有更多的内容。
下面从一个函数来说明,这个raw格式的文件是怎么回事。
1 bool loadRAWfile(const char* filename, RAWImportCallback& cb, PxReal scale) 2 { 3 FILE* fp = NULL; 4 physx::fopen_s(&fp, filename, "rb"); 5 if(!fp) 6 return false; 7 8 // General info 从文件中读取的通用信息 9 const PxU32 tag = read32(fp); 10 const PxU32 generalVersion = read32(fp); 11 const PxU32 nbMaterials = read32(fp); 12 const PxU32 nbTextures = read32(fp); 13 const PxU32 nbMeshes = read32(fp); //mesh的部分数 14 const PxU32 nbShapes = read32(fp); 15 const PxU32 nbHelpers = read32(fp); 16 17 char objectName[512]; 18 19 // Textures 20 for(PxU32 i=0;i<nbTextures;i++) 21 { 22 RAWTexture data; 23 24 readName(fp, objectName); 25 data.mName = objectName; 26 data.mTransform = PxTransform::createIdentity(); // PT: texture transform not supported yet 27 data.mID = read32(fp); 28 29 RendererColorAlloc* pixels = NULL; 30 if(read8(fp)) 31 { 32 data.mWidth = read32(fp); 33 data.mHeight = read32(fp); 34 data.mHasAlpha = read8(fp)!=0; 35 const PxU32 nbPixels = data.mWidth*data.mHeight; 36 pixels = SAMPLE_NEW(RendererColorAlloc)[nbPixels]; 37 data.mPixels = pixels; 38 for(PxU32 i=0;i<nbPixels;i++) 39 { 40 pixels[i].r = read8(fp); 41 pixels[i].g = read8(fp); 42 pixels[i].b = read8(fp); 43 if(data.mHasAlpha) 44 pixels[i].a = read8(fp); 45 else 46 pixels[i].a = 0xff; 47 } 48 } 49 else 50 { 51 data.mWidth = 0; 52 data.mHeight = 0; 53 data.mHasAlpha = false; 54 data.mPixels = NULL; 55 } 56 57 cb.newTexture(data); 58 DELETEARRAY(pixels); 59 } 60 61 // Materials 62 for(PxU32 i=0;i<nbMaterials;i++) 63 { 64 RAWMaterial data; 65 data.mID = read32(fp); 66 data.mDiffuseID = read32(fp); 67 data.mOpacity = readFloat(fp); 68 data.mDoubleSided = read32(fp)!=0; 69 70 data.mAmbientColor.x = readFloat(fp); 71 data.mAmbientColor.y = readFloat(fp); 72 data.mAmbientColor.z = readFloat(fp); 73 74 data.mDiffuseColor.x = readFloat(fp); 75 data.mDiffuseColor.y = readFloat(fp); 76 data.mDiffuseColor.z = readFloat(fp); 77 78 data.mSpecularColor.x = readFloat(fp); 79 data.mSpecularColor.y = readFloat(fp); 80 data.mSpecularColor.z = readFloat(fp); 81 82 cb.newMaterial(data); 83 } 84 85 // Meshes 这个nbMeshes是凸包的个数 86 for(PxU32 i=0;i<nbMeshes;i++) 87 { 88 RAWMesh data; 89 90 readName(fp, objectName); 91 data.mName = objectName; 92 data.mTransform = readTransform(fp, scale); 93 // 94 data.mNbVerts = read32(fp); 95 data.mNbFaces = read32(fp); 96 const PxU32 hasVertexColors = read32(fp); 97 const PxU32 hasUVs = read32(fp); 98 data.mMaterialID = read32(fp); 99 100 PxVec3Alloc* tmpVerts = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts]; 101 PxVec3Alloc* tmpNormals = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts]; 102 PxVec3Alloc* tmpColors = NULL; 103 PxReal* tmpUVs = NULL; 104 105 data.mVerts = tmpVerts; 106 data.mVertexNormals = tmpNormals; 107 data.mVertexColors = NULL; 108 data.mUVs = NULL; 109 110 readVertices(fp, tmpVerts, data.mNbVerts, scale); 111 readNormals(fp, tmpNormals, data.mNbVerts); 112 113 if(hasVertexColors) 114 { 115 tmpColors = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts]; 116 data.mVertexColors = tmpColors; 117 readVertexColors(fp, tmpColors, data.mNbVerts); 118 } 119 120 if(hasUVs) 121 { 122 tmpUVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*data.mNbVerts*2); 123 data.mUVs = tmpUVs; 124 readUVs(fp, tmpUVs, data.mNbVerts); 125 } 126 127 PxU32* tmpIndices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*data.mNbFaces*3); 128 data.mIndices = tmpIndices; 129 fread(tmpIndices, 4*3*data.mNbFaces, 1, fp); 130 if(gFlip) 131 { 132 for(PxU32 j=0;j<data.mNbFaces*3;j++) 133 { 134 Flip(tmpIndices[j]); 135 } 136 } 137 138 cb.newMesh(data); 139 140 SAMPLE_FREE(tmpIndices); 141 SAMPLE_FREE(tmpUVs); 142 DELETEARRAY(tmpColors); 143 DELETEARRAY(tmpNormals); 144 DELETEARRAY(tmpVerts); 145 } 146 147 // Shapes 148 for(PxU32 i=0;i<nbShapes;i++) 149 { 150 RAWShape data; 151 152 readName(fp, objectName); 153 data.mName = objectName; 154 data.mTransform = readTransform(fp, scale); 155 // 156 data.mNbVerts = read32(fp); 157 PxVec3Alloc* tmp = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts]; 158 data.mVerts = tmp; 159 readVertices(fp, tmp, data.mNbVerts, scale); 160 161 cb.newShape(data); 162 163 DELETEARRAY(tmp); 164 } 165 166 // Helpers 167 for(PxU32 i=0;i<nbHelpers;i++) 168 { 169 RAWHelper data; 170 171 readName(fp, objectName); 172 data.mName = objectName; 173 data.mTransform = readTransform(fp, scale); 174 } 175 return true; 176 }
1.首先,从 physx::fopen_s(&fp, filename, "rb"); 看出,.raw格式文件是以二进制方式读取的。
这里的filename是 car2.raw,在PhysXSample中提供,大小为136k。
2.这几个read32(fp)分别从文件中读取到了,tag信息、通用版本信息、材质数目、纹理数目、Mesh数目、Shape数目、还有Helper的数目。
// General info 从文件中读取的通用信息 const PxU32 tag = read32(fp); const PxU32 generalVersion = read32(fp); const PxU32 nbMaterials = read32(fp); const PxU32 nbTextures = read32(fp); const PxU32 nbMeshes = read32(fp); //mesh的部分数 const PxU32 nbShapes = read32(fp); const PxU32 nbHelpers = read32(fp);
下面这个函数是在RawLoader.cpp里面定义的,其调用了fread(buffer, elemSize, count , stream),这里用的是fread( data, 4, 1, fb),表示一次从文件中读取4个字节,32位数据。
//从FILE中读32个字节,并返回 static PxU32 read32(FILE* fp) { PxU32 data; fread(&data, 4, 1, fp); if(gFlip) Flip(data); return data; }
文件的开头4个字节是RAW!,表示了文件的格式是raw。
接下来4个字节是generalVersion,表示版本号。
接下来4个字节是nbMaterials,表示材质数目。
接下来4个字节是nbTextTures,表示纹理数目。
接下来4个字节是nbMeshes,表示网格数目。
接下来4个字节是nbShapes,表示形状数目。
接下来4个字节是nbHelpers,表示帮助信息数目。
- 接下来文件中存储的是纹理信息。
根据从文件头中读取的纹理数目,来读取纹理数据:包含储存纹理的文件名(长度不定),纹理的ID(4个字节)。还有可能包含的纹理的宽度、高度、alpha值,以及RGB值等。
最后根据这些纹理data,来NewTexture。
- 接下来文件中存储的是材质信息。
根据从文件头中读取的材质数目,来读取材质数据:包括材质ID(4个字节),漫反射ID(4个字节),不透明度(浮点类型,4个字节),是否双面(bool类型,在文件中是2个字节),之后就是环境光、漫反射光和镜面反射光(高光)的三个颜色分量的值,各占4个字节,共(3*3*4)=9个字节。
最后根据这些材质data,来NewMaterial。
- 接下来文件中存储的是网格(Mesh)数据。
根据从文件头中读取的网格数目,来读取网格数据:包含储存网格的文件名(长度不定),网格的Transform(7*4个字节),顶点个数(4个字节),面片个数(4个字节),是否包含顶点颜色(bool型,4个字节),是否包含UV坐标(bool型,4个字节),材质的ID(4个字节),然后根据从之前文件中读取的顶点数目,来读取相应数目的顶点和法线。
下面根据是否包含顶点颜色和UV的情况,读取文件中存储的相应个数的顶点颜色和UV(这两个不一定有)。
然后是读取 (4*3*data.mNbFaces)个字节数的数据,这些包含的就是网格的顶点数据。
最后根据这些data,来NewMesh。
- 接下来文件中存储的是形状数据。
根据从文件头中读取的形状数目,来读取形状数据:包含存储形状的文件名(长度不定),形状的Transform(7*4个字节),然后是顶点的数目(4个字节),之后是根据顶点的数目,来读取(顶点数目*4)个字节的顶点数据。
最后根据这些data,来NewShape。
- 接下来文件中存储的是帮助信息。
根据从文件头中读取的帮助信息数目,来读取帮助信息:包含存储帮助信息的文件名(长度不定),帮助信息的Transform(7*4个字节)。然后就没有了,帮助信息比较简单。
Conclusion:这个RAW格式的文件,并非度娘说的和大家所认识的raw格式。而是一种nvidia自己搞的格式,可以看成是类似索引文件,其中包含索引信息(指向存储纹理、网格、形状等的文件),和一些其它的数据(包括各类数据的数目、顶点数据等等。)
题外话:本来打算弄清楚这个raw格式是怎么回事之后,把这个用起来。结果弄完发现是这么个货,要用这个raw格式,就必须用到RawLoader,虽然提供了源文件,但是你以为他是独立的吗?拿过去就能用了?图样图森破!他里面包含了PhysXSample里面的newTexture之类的回调函数啊。最重要的是,这raw格式的东西没几个呀,就车、天空,桥,车就只有一个样式。就算用起来了,到时候你的场景里面所有的车都长一样,你乐意啊?而且这个raw格式的东东,也不知道他们是怎么弄出来的,你想自己弄吧,还不行,上网搜吧,也没有。所以我决定要放弃使用这个东西,我还是回归我的3ds和flt吧,毕竟可以网上搜到大把,只是数据和车辆的结构(主要是轮子与车身)需要自己组织罢了。
——————————分割线—7月25号补充————————————
在继续研究了程序之后,发现这个raw文件包含的东西还真不少,就我关心的Mesh部分的数据来说,它包含了顶点的个数,mesh的个数,每一个顶点的数据,然后还有Transform!(在车轮的Mesh里面,Transform表示了车轮的位置)。Nvidia你弄这个Sample真的是逗我们玩呢。哼!