扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
从前面可以看到人物角色显示是比较重要的,也是比较复杂的。现在就来仔细地分析一下第二人生里的Mesh文件是怎么样读取的呢?可以显示出来如此逼真优秀的画面。如下图所示:
蔡军生
在Mesh文件保存的格式里,最常用的有两种格式:文本格式和二进制格式。文本格式就是占用空间比较大,并且读取文件的数据也比较慢,但它便于查看。二进制格式是刚好相反的,在第二人生里使用的是二进制的文件格式。它的读取代码如下:
#001 BOOL LLPolyMeshSharedData::loadMesh( const char *fileName )
#002 {
#003 //-------------------------------------------------------------------------
#004 // Open the file
#005 //-------------------------------------------------------------------------
#006 if(!fileName)
#007 {
#008 llerrs << "Filename is Empty!" << llendl;
#009 return FALSE;
#010 }
上面判断文件名称是否有效。
#011 FILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
#012 if (!fp)
#013 {
#014 llerrs << "can't open: " << fileName << llendl;
#015 return FALSE;
#016 }
以只读的方式打开文件。
#017
#018 //-------------------------------------------------------------------------
#019 // Read a chunk
#020 //-------------------------------------------------------------------------
#021 char header[128]; /*Flawfinder: ignore*/
#022 if (fread(header, sizeof(char), 128, fp) != 128)
#023 {
#024 llwarns << "Short read" << llendl;
#025 }
读取第一块数据,大小为128个字节。这里也就是读取文件头。
#026
#027 //-------------------------------------------------------------------------
#028 // Check for proper binary header
#029 //-------------------------------------------------------------------------
#030 BOOL status = FALSE;
#031 if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
#032 {
上面是判断文件的版本。
#033 lldebugs << "Loading " << fileName << llendl;
#034
#035 //----------------------------------------------------------------
#036 // File Header (seek past it)
#037 //----------------------------------------------------------------
#038 fseek(fp, 24, SEEK_SET);
移动文件指针到合适的位置。
#039
#040 //----------------------------------------------------------------
#041 // HasWeights
#042 //----------------------------------------------------------------
#043 U8 hasWeights;
#044 size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
#045 if (numRead != 1)
#046 {
#047 llerrs << "can't read HasWeights flag from " << fileName << llendl;
#048 return FALSE;
#049 }
#050 if (!isLOD())
#051 {
#052 mHasWeights = (hasWeights==0) ? FALSE : TRUE;
#053 }
读取重量标志。
#054
#055 //----------------------------------------------------------------
#056 // HasDetailTexCoords
#057 //----------------------------------------------------------------
#058 U8 hasDetailTexCoords;
#059 numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
#060 if (numRead != 1)
#061 {
#062 llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
#063 return FALSE;
#064 }
读取是否有详细纹理坐标。
#065
#066 //----------------------------------------------------------------
#067 // Position
#068 //----------------------------------------------------------------
#069 LLVector3 position;
#070 numRead = fread(position.mV, sizeof(float), 3, fp);
#071 llendianswizzle(position.mV, sizeof(float), 3);
#072 if (numRead != 3)
#073 {
#074 llerrs << "can't read Position from " << fileName << llendl;
#075 return FALSE;
#076 }
#077 setPosition( position );
读取网格所在的位置。
#078
#079 //----------------------------------------------------------------
#080 // Rotation
#081 //----------------------------------------------------------------
#082 LLVector3 rotationAngles;
#083 numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
#084 llendianswizzle(rotationAngles.mV, sizeof(float), 3);
#085 if (numRead != 3)
#086 {
#087 llerrs << "can't read RotationAngles from " << fileName << llendl;
#088 return FALSE;
#089 }
读取网格旋转的角度。
#090
#091 U8 rotationOrder;
#092 numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
#093
#094 if (numRead != 1)
#095 {
#096 llerrs << "can't read RotationOrder from " << fileName << llendl;
#097 return FALSE;
#098 }
#099
#100 rotationOrder = 0;
#101
#102 setRotation( mayaQ( rotationAngles.mV[0],
#103 rotationAngles.mV[1],
#104 rotationAngles.mV[2],
#105 (LLQuaternion::Order)rotationOrder ) );
读取网格旋转顺序。
#106
#107 //----------------------------------------------------------------
#108 // Scale
#109 //----------------------------------------------------------------
#110 LLVector3 scale;
#111 numRead = fread(scale.mV, sizeof(float), 3, fp);
#112 llendianswizzle(scale.mV, sizeof(float), 3);
#113 if (numRead != 3)
#114 {
#115 llerrs << "can't read Scale from " << fileName << llendl;
#116 return FALSE;
#117 }
#118 setScale( scale );
读取网格缩放的大小。
#119
#120 //-------------------------------------------------------------------------
#121 // Release any existing mesh geometry
#122 //-------------------------------------------------------------------------
#123 freeMeshData();
#124
#125 U16 numVertices = 0;
#126
#127 //----------------------------------------------------------------
#128 // NumVertices
#129 //----------------------------------------------------------------
#130 if (!isLOD())
#131 {
#132 numRead = fread(&numVertices, sizeof(U16), 1, fp);
#133 llendianswizzle(&numVertices, sizeof(U16), 1);
#134 if (numRead != 1)
#135 {
#136 llerrs << "can't read NumVertices from " << fileName << llendl;
#137 return FALSE;
#138 }
#139
#140 allocateVertexData( numVertices );
读取网格的顶点数量,并分配顶点保存数据的内存。
#141
#142 //----------------------------------------------------------------
#143 // Coords
#144 //----------------------------------------------------------------
#145 numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
#146 llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
#147 if (numRead != numVertices)
#148 {
#149 llerrs << "can't read Coordinates from " << fileName << llendl;
#150 return FALSE;
#151 }
#152
上面读取网格所有顶点的坐标值。每个坐标有三个浮点数组成。
#153 //----------------------------------------------------------------
#154 // Normals
#155 //----------------------------------------------------------------
#156 numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
#157 llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
#158 if (numRead != numVertices)
#159 {
#160 llerrs << " can't read Normals from " << fileName << llendl;
#161 return FALSE;
#162 }
读取网格的顶点法向量。
#163
#164 //----------------------------------------------------------------
#165 // Binormals
#166 //----------------------------------------------------------------
#167 numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
#168 llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
#169 if (numRead != numVertices)
#170 {
#171 llerrs << " can't read Binormals from " << fileName << llendl;
#172 return FALSE;
#173 }
读取网格的副法线向量。
#174
#175
#176 //----------------------------------------------------------------
#177 // TexCoords
#178 //----------------------------------------------------------------
#179 numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
#180 llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
#181 if (numRead != numVertices)
#182 {
#183 llerrs << "can't read TexCoords from " << fileName << llendl;
#184 return FALSE;
#185 }
读取每个顶点的纹理坐标值。
#186
#187 //----------------------------------------------------------------
#188 // DetailTexCoords
#189 //----------------------------------------------------------------
#190 if (mHasDetailTexCoords)
#191 {
#192 numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
#193 llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
#194 if (numRead != numVertices)
#195 {
#196 llerrs << "can't read DetailTexCoords from " << fileName << llendl;
#197 return FALSE;
#198 }
#199 }
读取详细纹理坐标值。
#200
#201 //----------------------------------------------------------------
#202 // Weights
#203 //----------------------------------------------------------------
#204 if (mHasWeights)
#205 {
#206 numRead = fread(mWeights, sizeof(float), numVertices, fp);
#207 llendianswizzle(mWeights, sizeof(float), numVertices);
#208 if (numRead != numVertices)
#209 {
#210 llerrs << "can't read Weights from " << fileName << llendl;
#211 return FALSE;
#212 }
#213 }
#214 }
读取每个顶点重量。
#215
#216 //----------------------------------------------------------------
#217 // NumFaces
#218 //----------------------------------------------------------------
#219 U16 numFaces;
#220 numRead = fread(&numFaces, sizeof(U16), 1, fp);
#221 llendianswizzle(&numFaces, sizeof(U16), 1);
#222 if (numRead != 1)
#223 {
#224 llerrs << "can't read NumFaces from " << fileName << llendl;
#225 return FALSE;
#226 }
#227 allocateFaceData( numFaces );
读取网格的表面个数,并分配所有表面内存。
#228
#229
#230 //----------------------------------------------------------------
#231 // Faces
#232 //----------------------------------------------------------------
#233 U32 i;
#234 U32 numTris = 0;
#235 for (i = 0; i < numFaces; i++)
#236 {
#237 S16 face[3];
#238 numRead = fread(face, sizeof(U16), 3, fp);
#239 llendianswizzle(face, sizeof(U16), 3);
#240 if (numRead != 3)
#241 {
#242 llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
#243 return FALSE;
#244 }
#245 if (mReferenceData)
#246 {
#247 llassert(face[0] < mReferenceData->mNumVertices);
#248 llassert(face[1] < mReferenceData->mNumVertices);
#249 llassert(face[2] < mReferenceData->mNumVertices);
#250 }
#251
#252 if (isLOD())
#253 {
#254 // store largest index in case of LODs
#255 for (S32 j = 0; j < 3; j++)
#256 {
#257 if (face[j] > mNumVertices - 1)
#258 {
#259 mNumVertices = face[j] + 1;
#260 }
#261 }
#262 }
#263 mFaces[i][0] = face[0];
#264 mFaces[i][1] = face[1];
#265 mFaces[i][2] = face[2];
#266
#267 // S32 j;
#268 // for(j = 0; j < 3; j++)
#269 // {
#270 // LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
#271 // if (!face_list)
#272 // {
#273 // face_list = new LLDynamicArray<S32>;
#274 // mVertFaceMap.addData(face[j], face_list);
#275 // }
#276 // face_list->put(i);
#277 // }
#278
#279 numTris++;
#280 }
#281
#282 lldebugs << "verts: " << numVertices
#283 << ", faces: " << numFaces
#284 << ", tris: " << numTris
#285 << llendl;
上面读取每个表面的索引值。
#286
#287 //----------------------------------------------------------------
#288 // NumSkinJoints
#289 //----------------------------------------------------------------
#290 if (!isLOD())
#291 {
#292 U16 numSkinJoints = 0;
#293 if ( mHasWeights )
#294 {
#295 numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
#296 llendianswizzle(&numSkinJoints, sizeof(U16), 1);
#297 if (numRead != 1)
#298 {
#299 llerrs << "can't read NumSkinJoints from " << fileName << llendl;
#300 return FALSE;
#301 }
#302 allocateJointNames( numSkinJoints );
#303 }
读取有多少个联接名称。
#304
#305 //----------------------------------------------------------------
#306 // SkinJoints
#307 //----------------------------------------------------------------
#308 for (i=0; i < numSkinJoints; i++)
#309 {
#310 char jointName[64+1];
#311 numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
#312 jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
#313 if (numRead != 1)
#314 {
#315 llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
#316 return FALSE;
#317 }
#318
#319 std::string *jn = &mJointNames[i];
#320 *jn = jointName;
#321 }
#322
读取联接名称。
#323 //-------------------------------------------------------------------------
#324 // look for morph section
#325 //-------------------------------------------------------------------------
#326 char morphName[64+1];
#327 morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
#328 while(fread(&morphName, sizeof(char), 64, fp) == 64)
#329 {
#330 if (!strcmp(morphName, "End Morphs"))
#331 {
#332 // we reached the end of the morphs
#333 break;
#334 }
#335 LLPolyMorphData* morph_data = new LLPolyMorphData(morphName);
#336
#337 BOOL result = morph_data->loadBinary(fp, this);
#338
#339 if (!result)
#340 {
#341 delete morph_data;
#342 continue;
#343 }
#344
#345 mMorphData.addData(morph_data);
#346 }
#347
#348 S32 numRemaps;
#349 if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
#350 {
#351 llendianswizzle(&numRemaps, sizeof(S32), 1);
#352 for (S32 i = 0; i < numRemaps; i++)
#353 {
#354 S32 remapSrc;
#355 S32 remapDst;
#356 if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
#357 {
#358 llerrs << "can't read source vertex in vertex remap data" << llendl;
#359 break;
#360 }
#361 if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
#362 {
#363 llerrs << "can't read destination vertex in vertex remap data" << llendl;
#364 break;
#365 }
#366 llendianswizzle(&remapSrc, sizeof(S32), 1);
#367 llendianswizzle(&remapDst, sizeof(S32), 1);
#368
#369 mSharedVerts[remapSrc] = remapDst;
#370 }
#371 }
#372 }
上面读取动画方面的数据。
#373
#374 status = TRUE;
#375 }
#376 else
#377 {
#378 llerrs << "invalid mesh file header: " << fileName << llendl;
#379 status = FALSE;
#380 }
#381
#382 if (0 == mNumJointNames)
#383 {
#384 allocateJointNames(1);
#385 }
#386
#387 fclose( fp );
#388
#389 return status;
#390 }
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者