Creating a Texture From a File
KFbxTexture is the base class for textures in the FBX SDK. Textures rely on an underlying material to influence how the geometry is rendered. In the following code sample, we associate the diffuse, ambient and emissive channels of a Phong material to three distinct instances of KFbxFileTexture. KFbxFileTexture represents any texture loaded from a file. For more information on referencing embedded or non-embedded media in files, see Referencing Media.
// Create texture for cube. void CreateTexture(KFbxScene* pScene, KFbxMesh* pMesh) { // A texture need to be connected to a property on the material, // so let's use the material (if it exists) or create a new one KFbxSurfacePhong* lMaterial = NULL; //get the node of mesh, add material for it. KFbxNode* lNode = pMesh->GetNode(); if(lNode) { lMaterial = lNode->GetSrcObject<KFbxSurfacePhong>(0); if (lMaterial == NULL) { KString lMaterialName = "toto"; KString lShadingName = "Phong"; fbxDouble3 lBlack(0.0, 0.0, 0.0); fbxDouble3 lRed(1.0, 0.0, 0.0); fbxDouble3 lDiffuseColor(0.75, 0.75, 0.0); lMaterial = KFbxSurfacePhong::Create(pScene, lMaterialName.Buffer()); // Generate primary and secondary colors. lMaterial->Emissive .Set(lBlack); lMaterial->Ambient .Set(lRed); lMaterial->AmbientFactor .Set(1.); // Add texture for diffuse channel lMaterial->Diffuse .Set(lDiffuseColor); lMaterial->DiffuseFactor .Set(1.); lMaterial->TransparencyFactor.Set(0.4); lMaterial->ShadingModel .Set(lShadingName); lMaterial->Shininess .Set(0.5); lMaterial->Specular .Set(lBlack); lMaterial->SpecularFactor .Set(0.3); lNode->AddMaterial(lMaterial); } } KFbxFileTexture* lTexture = KFbxFileTexture::Create(pScene,"Diffuse Texture"); // Set texture properties. lTexture->SetFileName("scene03.jpg"); // Resource file is in current directory. lTexture->SetTextureUse(KFbxTexture::eSTANDARD); lTexture->SetMappingType(KFbxTexture::eUV); lTexture->SetMaterialUse(KFbxFileTexture::eMODEL_MATERIAL); lTexture->SetSwapUV(false); lTexture->SetTranslation(0.0, 0.0); lTexture->SetScale(1.0, 1.0); lTexture->SetRotation(0.0, 0.0); // don't forget to connect the texture to the corresponding property of the material if (lMaterial) lMaterial->Diffuse.ConnectSrcObject(lTexture); lTexture = KFbxFileTexture::Create(pScene,"Ambient Texture"); // Set texture properties. lTexture->SetFileName("gradient.jpg"); // Resource file is in current directory. lTexture->SetTextureUse(KFbxTexture::eSTANDARD); lTexture->SetMappingType(KFbxTexture::eUV); lTexture->SetMaterialUse(KFbxFileTexture::eMODEL_MATERIAL); lTexture->SetSwapUV(false); lTexture->SetTranslation(0.0, 0.0); lTexture->SetScale(1.0, 1.0); lTexture->SetRotation(0.0, 0.0); // don't forget to connect the texture to the corresponding property of the material if (lMaterial) lMaterial->Ambient.ConnectSrcObject(lTexture); lTexture = KFbxFileTexture::Create(pScene,"Emissive Texture"); // Set texture properties. lTexture->SetFileName("spotty.jpg"); // Resource file is in current directory. lTexture->SetTextureUse(KFbxTexture::eSTANDARD); lTexture->SetMappingType(KFbxTexture::eUV); lTexture->SetMaterialUse(KFbxFileTexture::eMODEL_MATERIAL); lTexture->SetSwapUV(false); lTexture->SetTranslation(0.0, 0.0); lTexture->SetScale(1.0, 1.0); lTexture->SetRotation(0.0, 0.0); // don't forget to connect the texture to the corresponding property of the material if (lMaterial) lMaterial->Emissive.ConnectSrcObject(lTexture); }
Example: Creating a Textured Cube
The following code sample makes use of the CreateTexture() function we defined above. We first begin by defining the control points and normals of the cube.
// Create a cube with a texture. KFbxNode* CreateCubeWithTexture(KFbxScene* pScene, char* pName) { int i, j; KFbxMesh* lMesh = KFbxMesh::Create(pScene,pName); KFbxVector4 lControlPoint0(-50, 0, 50); KFbxVector4 lControlPoint1(50, 0, 50); KFbxVector4 lControlPoint2(50, 100, 50); KFbxVector4 lControlPoint3(-50, 100, 50); KFbxVector4 lControlPoint4(-50, 0, -50); KFbxVector4 lControlPoint5(50, 0, -50); KFbxVector4 lControlPoint6(50, 100, -50); KFbxVector4 lControlPoint7(-50, 100, -50); KFbxVector4 lNormalXPos(1, 0, 0); KFbxVector4 lNormalXNeg(-1, 0, 0); KFbxVector4 lNormalYPos(0, 1, 0); KFbxVector4 lNormalYNeg(0, -1, 0); KFbxVector4 lNormalZPos(0, 0, 1); KFbxVector4 lNormalZNeg(0, 0, -1); // Create control points. lMesh->InitControlPoints(24); KFbxVector4* lControlPoints = lMesh->GetControlPoints(); lControlPoints[0] = lControlPoint0; lControlPoints[1] = lControlPoint1; lControlPoints[2] = lControlPoint2; lControlPoints[3] = lControlPoint3; lControlPoints[4] = lControlPoint1; lControlPoints[5] = lControlPoint5; lControlPoints[6] = lControlPoint6; lControlPoints[7] = lControlPoint2; lControlPoints[8] = lControlPoint5; lControlPoints[9] = lControlPoint4; lControlPoints[10] = lControlPoint7; lControlPoints[11] = lControlPoint6; lControlPoints[12] = lControlPoint4; lControlPoints[13] = lControlPoint0; lControlPoints[14] = lControlPoint3; lControlPoints[15] = lControlPoint7; lControlPoints[16] = lControlPoint3; lControlPoints[17] = lControlPoint2; lControlPoints[18] = lControlPoint6; lControlPoints[19] = lControlPoint7; lControlPoints[20] = lControlPoint1; lControlPoints[21] = lControlPoint0; lControlPoints[22] = lControlPoint4; lControlPoints[23] = lControlPoint5; // We want to have one normal for each vertex (or control point), // so we set the mapping mode to eBY_CONTROL_POINT. KFbxGeometryElementNormal* lGeometryElementNormal= lMesh->CreateElementNormal(); lGeometryElementNormal->SetMappingMode(KFbxGeometryElement::eBY_CONTROL_POINT); // Here are two different ways to set the normal values. bool firstWayNormalCalculations=true; if (firstWayNormalCalculations) { // The first method is to set the actual normal value // for every control point. lGeometryElementNormal->SetReferenceMode(KFbxGeometryElement::eDIRECT); lGeometryElementNormal->GetDirectArray().Add(lNormalZPos); lGeometryElementNormal->GetDirectArray().Add(lNormalZPos); lGeometryElementNormal->GetDirectArray().Add(lNormalZPos); lGeometryElementNormal->GetDirectArray().Add(lNormalZPos); lGeometryElementNormal->GetDirectArray().Add(lNormalXPos); lGeometryElementNormal->GetDirectArray().Add(lNormalXPos); lGeometryElementNormal->GetDirectArray().Add(lNormalXPos); lGeometryElementNormal->GetDirectArray().Add(lNormalXPos); lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalYPos); lGeometryElementNormal->GetDirectArray().Add(lNormalYPos); lGeometryElementNormal->GetDirectArray().Add(lNormalYPos); lGeometryElementNormal->GetDirectArray().Add(lNormalYPos); lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg); } else { // The second method is to the possible values of the normals // in the direct array, and set the index of that value // in the index array for every control point. lGeometryElementNormal->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT); // Add the 6 different normals to the direct array lGeometryElementNormal->GetDirectArray().Add(lNormalZPos); lGeometryElementNormal->GetDirectArray().Add(lNormalXPos); lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg); lGeometryElementNormal->GetDirectArray().Add(lNormalYPos); lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg); // Now for each control point, we need to specify which normal to use lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array. lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array. lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array. }
We then call KFbxMesh::CreateElementUV() to create three new texture layers in the mesh - one for each of the diffuse, ambient, and emissive material channels. The resulting texture layer elements (KFbxGeometryElementUV) define how to map the texture's UV coordinates to each of the polygon's vertices. Lastly, we call KFbxNode::SetShadingMode() with the value KFbxNode::eTEXTURE_SHADING to allow our textures to be rendered in the scene.
// Array of polygon vertices. int lPolygonVertices[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; // Create UV for Diffuse channel KFbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV( "DiffuseUV"); K_ASSERT( lUVDiffuseElement != NULL); lUVDiffuseElement->SetMappingMode(KFbxGeometryElement::eBY_POLYGON_VERTEX); lUVDiffuseElement->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT); KFbxVector2 lVectors0(0, 0); KFbxVector2 lVectors1(1, 0); KFbxVector2 lVectors2(1, 1); KFbxVector2 lVectors3(0, 1); lUVDiffuseElement->GetDirectArray().Add(lVectors0); lUVDiffuseElement->GetDirectArray().Add(lVectors1); lUVDiffuseElement->GetDirectArray().Add(lVectors2); lUVDiffuseElement->GetDirectArray().Add(lVectors3); // Create UV for Ambient channel KFbxGeometryElementUV* lUVAmbientElement = lMesh->CreateElementUV("AmbientUV"); lUVAmbientElement->SetMappingMode(KFbxGeometryElement::eBY_POLYGON_VERTEX); lUVAmbientElement->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT); lVectors0.Set(0, 0); lVectors1.Set(1, 0); lVectors2.Set(0, 0.418586879968643); lVectors3.Set(1, 0.418586879968643); lUVAmbientElement->GetDirectArray().Add(lVectors0); lUVAmbientElement->GetDirectArray().Add(lVectors1); lUVAmbientElement->GetDirectArray().Add(lVectors2); lUVAmbientElement->GetDirectArray().Add(lVectors3); // Create UV for Emissive channel KFbxGeometryElementUV* lUVEmissiveElement = lMesh->CreateElementUV("EmissiveUV"); lUVEmissiveElement->SetMappingMode(KFbxGeometryElement::eBY_POLYGON_VERTEX); lUVEmissiveElement->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT); lVectors0.Set(0.2343, 0); lVectors1.Set(1, 0.555); lVectors2.Set(0.333, 0.999); lVectors3.Set(0.555, 0.666); lUVEmissiveElement->GetDirectArray().Add(lVectors0); lUVEmissiveElement->GetDirectArray().Add(lVectors1); lUVEmissiveElement->GetDirectArray().Add(lVectors2); lUVEmissiveElement->GetDirectArray().Add(lVectors3); //Now we have set the UVs as eINDEX_TO_DIRECT reference and in eBY_POLYGON_VERTEX mapping mode //we must update the size of the index array. lUVDiffuseElement->GetIndexArray().SetCount(24); lUVAmbientElement->GetIndexArray().SetCount(24); lUVEmissiveElement->GetIndexArray().SetCount(24); // Create polygons. Assign texture and texture UV indices. for(i = 0; i < 6; i++) { //we won't use the default way of assigning textures, as we have //textures on more than just the default (diffuse) channel. lMesh->BeginPolygon(-1, -1, false); for(j = 0; j < 4; j++) { //this function points lMesh->AddPolygon(lPolygonVertices[i*4 + j] // Control point index. ); //Now we have to update the index array of the UVs for diffuse, ambient and emissive lUVDiffuseElement->GetIndexArray().SetAt(i*4+j, j); lUVAmbientElement->GetIndexArray().SetAt(i*4+j, j); lUVEmissiveElement->GetIndexArray().SetAt(i*4+j, j); } lMesh->EndPolygon (); } KFbxNode* lNode = KFbxNode::Create(pScene,pName); lNode->SetNodeAttribute(lMesh); lNode->SetShadingMode(KFbxNode::eTEXTURE_SHADING); CreateTexture(pScene, lMesh); return lNode; }