Fbx model parsing and loading based on fbx SDK-(2)

Source: Internet
Author: User
5. Load Materials

Material is an essential part of model rendering. Of course, this information is also stored in fbx (even various textures can be directly embedded in fbx ), you need to load the information from fbx to complete rendering with materials. Material loading can be combined with mesh loading, but a better way is to perform it independently, so that the relationship between modules is clearer, but this requires an additional operation, that is, the associated mesh and material. Material objects in fbx contain rich information, such as the most common material attributes in Max, such as ambient, diffuse, specular color and texture; shininess and opacity values, more advanced attributes such as effect parameters and source files can be saved. It tries its best to ensure that material information is not lost when exported from the modeling tool, but can be read selectively during use.

5.1 associated mesh and material

For systems loaded independently by material and mesh, you must first read the relevant information to associate the two. These information is actually stored in the kfbxmesh (part of the geometric information ). Each mesh node with materials will contain a node of the kfbxgeometryelementmaterial type (this node is blank if materials are not included ), this node records the ing between the polygon (all triangles here) in the mesh and each material. Read the information in this node to establish the connection between the mesh and material. The Code is as follows:

void ConnectMaterialToMesh(KFbxMesh* pMesh , int triangleCount , int* pTriangleMtlIndex){// Get the material index list of current meshKFbxLayerElementArrayTemplate<int>* pMaterialIndices;KFbxGeometryElement::EMappingMode   materialMappingMode = KFbxGeometryElement::eNONE;if(pMesh->GetElementMaterial()){pMaterialIndices    = &pMesh->GetElementMaterial()->GetIndexArray();materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();if(pMaterialIndices){switch(materialMappingMode){case KFbxGeometryElement::eBY_POLYGON:{if(pMaterialIndices->GetCount() == triangleCount){for(int triangleIndex = 0 ; triangleIndex < triangleCount ; ++triangleIndex){int materialIndex = pMaterialIndices->GetAt(triangleIndex);pTriangleMtlIndex[triangleIndex] = materialIndex;}}}break;case KFbxGeometryElement::eALL_SAME:{int lMaterialIndex = pMaterialIndices->GetAt(0);for(int triangleIndex = 0 ; triangleIndex < triangleCount ; ++triangleIndex){int materialIndex = pMaterialIndices->GetAt(triangleIndex);pTriangleMtlIndex[triangleIndex] = materialIndex;}}}}}}

Trianglecount indicates the number of triangles read from pmesh. ptrianglemtlindex is an array with a length of trianglecount. It is mainly used to store the material indexes corresponding to the retrieved triangles. Note: The problem is that a triangle corresponds to only one material, but this is also true in general (if it corresponds to multiple materials, you need to modify the code here ). After the mesh index is read, the values in ptrianglemtlindex can be dumped to the corresponding Triangle List in an appropriate way (or in other ways) for rendering.

5.2 normal material

In fbx, the actual location for storing material information is a kfbxsurfacematerial node corresponding to each mesh, which stores the typical information of common materials, it mainly includes the following attributes (some of which are not listed ):

  • ShadingmodelThe illumination model of materials, generally two typical local illumination models: Phong and Lambert.
  • EmissiveEmissive attributes
  • Emissivefactor
  • AmbientAmbient attributes
  • Ambientfactor
  • DiffuseDiffuse attributes
  • Diffusefactor
  • SpecularSpecular attributes
  • Specularfactor
  • ShininessSepcular shininess attributes
  • BumpAttributes related to normal map
  • Normalmap
  • Bumpfactor
  • TransparentcolorTransparent attributes
  • Transparencyfactor
  • ReflectionReflection attributes
  • Reflectionfactor

Of course, in actual applications, these attributes do not need to be fully read. You can select to read the attributes as needed. The material reading code is described as follows (simple version ):

void LoadMaterial(KFbxMesh* pMesh){int materialCount;KFbxNode* pNode;if(pMesh && pMesh->GetNode()){pNode         = pMesh->GetNode();materialCount = pNode->GetMaterialCount();}if(materialCount > 0){for(int materialIndex = 0 ; materialIndex < materialCount ; materialIndex++){KFbxSurfaceMaterial* pSurfaceMaterial = pNode->GetMaterial(materialIndex);LoadMaterialAttribute(pSurfaceMaterial);}}}
void LoadMaterialAttribute(KFbxSurfaceMaterial* pSurfaceMaterial){// Get the name of materialpSurfaceMaterial->GetName();// Phong materialif(pSurfaceMaterial->GetClassId().Is(KFbxSurfacePhong::ClassId)){// Ambient ColorfbxDouble3 = ((KFbxSurfacePhong*)pSurfaceMaterial)->Ambient;// ...// Diffuse ColorfbxDouble3 =((KFbxSurfacePhong*)pSurfaceMaterial)->Diffuse;// ...// Specular ColorfbxDouble3 =((KFbxSurfacePhong*)pSurfaceMaterial)->Specular;// ...// Emissive ColorfbxDouble3 =((KFbxSurfacePhong*)pSurfaceMaterial)->Emissive;// ...// OpacityfbxDouble1 =((KFbxSurfacePhong*)pSurfaceMaterial)->TransparencyFactor;// ...// ShininessfbxDouble1 =((KFbxSurfacePhong*)pSurfaceMaterial)->Shininess;// ...// ReflectivityfbxDouble1 =((KFbxSurfacePhong*)pSurfaceMaterial)->ReflectionFactor;// ...return;}// Lambert materialif(pSurfaceMaterial->GetClassId().Is(KFbxSurfaceLambert::ClassId)){// Ambient ColorfbxDouble3=((KFbxSurfaceLambert*)pSurfaceMaterial)->Ambient;// ...// Diffuse ColorfbxDouble3 =((KFbxSurfaceLambert*)pSurfaceMaterial)->Diffuse;// ...// Emissive ColorfbxDouble3 =((KFbxSurfaceLambert*)pSurfaceMaterial)->Emissive;// ...// OpacityfbxDouble1 =((KFbxSurfaceLambert*)pSurfaceMaterial)->TransparencyFactor;// ...return;}}

The above code can load common attributes. In addition, the texture associated with the material also needs to be loaded. This operation is generally combined with a Texture Manager to form a reasonable association between all texture and material, the operations in this step are generally described in the following code:

void LoadMaterialTexture(KFbxSurfaceMaterial* pSurfaceMaterial){int textureLayerIndex;KFbxProperty pProperty;int texID;MaterialTextureDesc::MtlTexTypeEnum texType;for(textureLayerIndex = 0 ; textureLayerIndex < KFbxLayerElement::LAYERELEMENT_TYPE_TEXTURE_COUNT ; ++textureLayerIndex){pProperty = pSurfaceMaterial->FindProperty(KFbxLayerElement::TEXTURE_CHANNEL_NAMES[textureLayerIndex]);if(pProperty.IsValid()){int textureCount = pProperty.GetSrcObjectCount(KFbxTexture::ClassId);for(int j = 0 ; j < textureCount ; ++j){KFbxTexture* pTexture = KFbxCast<KFbxTexture>(pProperty.GetSrcObject(KFbxTexture::ClassId,j));if(pTexture){// Use pTexture to load the attribute of current texture...}}}}}
5.3 hardware-related materials and effect

Kids shoes with modeling experience know that in 3D Max or Maya, you can specify specific shader for certain materials to achieve specific effects, these models will also save the corresponding hardware-related shader to the fbx model. Therefore, special code is required for loading materials with such properties. Fbx supports embedding CG, HLSL, glsl, and other mainstream coloring languages, which are easy to obtain during parsing.

void LoadMaterialAttribute(KFbxSurfaceMaterial* pSurfaceMaterial){KFbxImplementation* pImplementation;KString implemenationType;pImplementation = GetImplementation(pSurfaceMaterial , ImplementationHLSL);KString implemenationType = "HLSL";if(pImplementation){LoadMaterialEffect(pSurfaceMaterial , pImplementation , &implemenationType);}}

The above code can be combined with the Code read from the previous material attribute. Fbx generally associates hardware-related shader with material through an object of the kfbximplementation type. You can use the above Code to obtain the association between the two, implementationhlsl is a macro that identifies the HLSL type shader. If it is CG, implementationcgfx is used. If the current material contains the HLSL type shader, a non-null kfbximplementation pointer can be obtained, and the attributes of the shader can be parsed. Otherwise, the pointer is null, indicating that some materials are associated with other similar shader or do not contain shader. The code used to obtain the attribute of effect through kfbximplementation is as follows:

void LoadMaterialEffect(KFbxSurfaceMaterial* pSurfaceMaterial , const KFbxImplementation* pImplementation , KString* pImplemenationType){KFbxBindingTable const* lRootTable = pImplementation->GetRootTable();fbxString lFileName                = lRootTable->DescAbsoluteURL.Get();fbxString lTechniqueName           = lRootTable->DescTAG.Get();// Name of the effect filelFileName.Buffer();KFbxBindingTable const* pBTable = pImplementation->GetRootTable();size_t entryCount = pBTable->GetEntryCount();for(size_t i = 0 ; i < entryCount ; ++i){const KFbxBindingTableEntry& btEntry = pBTable->GetEntry(i);const char* pEntrySrcType = btEntry.GetEntryType(true);KFbxProperty fbxProperty;// Name of ParameterbtEntry.GetDestination();// Semantic of ParameterbtEntry.GetDestination();if(strcmp(KFbxPropertyEntryView::sEntryType , pEntrySrcType) == 0){fbxProperty = pSurfaceMaterial->FindPropertyHierarchical(btEntry.GetSource());if(!fbxProperty.IsValid()){fbxProperty = pSurfaceMaterial->RootProperty.FindHierarchical(btEntry.GetSource());}}else{if(strcmp(KFbxConstantEntryView::sEntryType , pEntrySrcType) == 0){fbxProperty = pImplementation->GetConstants().FindHierarchical(btEntry.GetSource());}}if(fbxProperty.IsValid()){if(fbxProperty.GetSrcObjectCount(FBX_TYPE(KFbxTexture)) > 0){// Texture Parameterfor(int j = 0 ; j < fbxProperty.GetSrcObjectCount(FBX_TYPE(KFbxFileTexture)) ; ++j){KFbxFileTexture* pFileTexture = fbxProperty.GetSrcObject(FBX_TYPE(KFbxFileTexture) , j);}for(int j = 0 ; j < fbxProperty.GetSrcObjectCount(FBX_TYPE(KFbxLayeredTexture)) ; ++j){KFbxLayeredTexture* pLayeredTexture = fbxProperty.GetSrcObject(FBX_TYPE(KFbxLayeredTexture) , j);}for(int j = 0 ; j < fbxProperty.GetSrcObjectCount(FBX_TYPE(KFbxProceduralTexture)) ; ++j){KFbxProceduralTexture* pProceduralTexture = fbxProperty.GetSrcObject(FBX_TYPE(KFbxProceduralTexture) , j);}}else{// Common ParameterKFbxDataType dataType = fbxProperty.GetPropertyDataType();// Bool valueif(DTBool == dataType){bool boolValue = KFbxGet<bool>(fbxProperty);}// Integer valueif(DTInteger == dataType || DTEnum == dataType){int intValue = KFbxGet<int>(fbxProperty);}// Floatif(DTFloat == dataType){float floatValue = KFbxGet<float>(fbxProperty);}// Doubleif(DTDouble == dataType){double doubleValue = (float)KFbxGet<double>(fbxProperty);}// Double2if(DTDouble2 == dataType){fbxDouble2 lDouble2 = KFbxGet<fbxDouble2>(fbxProperty);D3DXVECTOR2 double2Value = D3DXVECTOR2((float)lDouble2[0] , (float)lDouble2[1]);}// Double3if(DTDouble3  == dataType || DTVector3D == dataType || DTColor3 == dataType){fbxDouble3 lDouble3 = KFbxGet<fbxDouble3>(fbxProperty);D3DXVECTOR3 double3Value = D3DXVECTOR3((float)lDouble3[0] , (float)lDouble3[1] , (float)lDouble3[2]);}// Double4if(DTDouble4  == dataType || DTVector4D == dataType || DTColor4 == dataType){fbxDouble4 lDouble4 = KFbxGet<fbxDouble4>(fbxProperty);D3DXVECTOR4 double4Value = D3DXVECTOR4((float)lDouble4[0] , (float)lDouble4[1] , (float)lDouble4[2] , (float)lDouble4[3]);}// Double4x4if(DTDouble44 == dataType){fbxDouble44 lDouble44 = KFbxGet<fbxDouble44>(fbxProperty);D3DXMATRIX double4x4Value;for(int i = 0 ; i < 4 ; ++i){for(int j = 0 ; j < 4 ; ++j){double4x4Value.m[i][j] = (float)lDouble44[i][j];}}}// Stringif(DTString == dataType || DTUrl == dataType || DTXRefUrl == dataType){char* pStringBuffer =(KFbxGet<fbxString>(fbxProperty)).Buffer();}}}}}

The main attributes of the parsed effect include the source file corresponding to the shader and the initial settings of various external parameters provided by the shader (for example, the parameters adjusted by the UI control in 3D MAX value ). The specific method code is already clear and I will not go into details here. The subsequent operations depend on how the data structure of the entire material and effect is organized and how the data structure can be integrated with your own code.

5.4 optimize mesh based on material

The fbx model obtained after fbx export is usually used to generate the scene graph of the entire file based on the geometric attribute, therefore, the ing relationship between the geometric mesh and material obtained by the above analysis may not be suitable for direct painting, and generally needs to be re-organized. For example, the ing relationship may be

  1. Triangle0-> Material1
  2. Triangle1-> material0
  3. Triangle2-> Material1
  4. ...

If the rendering process of an application uses the minimum number of switching times between material as the primary consideration for rendering, you cannot directly use the triangle sequence to generate the Rendering Buffer, material needs to be used to sort and reorganize the order of geometric data.

After loading the above, you can achieve the rendering effect with materials:


Next, we will introduce the reading of camera and light related to animation...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.