環境
python3.9 Fbx Sdk
概要
Python SDK 2020.3.2のsamplesのExportScene03.pyから立方体の作成部分を抽出したものです
サンプルのコードだとマテリアルが出力されないので修正
CreateTexture()の呼び出し位置をNodeに接続した後に変えています
このコードだと頂点数の多いよくわからない立方体ができるので、以下のリンクも参照する
Houdini ApprenticeでFbx出力 - テキトープログラム( ..)φメモ
import FbxCommon from fbx import * def CreateTexture(pSdkManager, pMesh): lMaterial = None lNode = pMesh.GetNode() lMaterial = lNode.GetSrcObject(FbxCriteria.ObjectType(FbxSurfacePhong.ClassId), 0) if not lMaterial: lMaterialName = "toto" lShadingName = "Phong" lBlack = FbxDouble3(0.0, 0.0, 0.0) lRed = FbxDouble3(1.0, 0.0, 0.0) lDiffuseColor = FbxDouble3(0.75, 0.75, 0.0) lMaterial = FbxSurfacePhong.Create(pSdkManager, lMaterialName) lMaterial.Emissive.Set(lBlack) lMaterial.Ambient.Set(lRed) lMaterial.AmbientFactor.Set(1.) 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) lTexture = FbxFileTexture.Create(pSdkManager,"Diffuse Texture") lTexture.SetFileName("scene03.jpg") # Resource file is in current directory. lTexture.SetTextureUse(FbxTexture.eStandard) lTexture.SetMappingType(FbxTexture.eUV) lTexture.SetMaterialUse(FbxFileTexture.eModelMaterial) lTexture.SetSwapUV(False) lTexture.SetTranslation(0.0, 0.0) lTexture.SetScale(1.0, 1.0) lTexture.SetRotation(0.0, 0.0) lMaterial.Diffuse.ConnectSrcObject(lTexture) lTexture = FbxFileTexture.Create(pSdkManager,"Ambient Texture") lTexture.SetFileName("gradient.jpg") # Resource file is in current directory. lTexture.SetTextureUse(FbxTexture.eStandard) lTexture.SetMappingType(FbxTexture.eUV) lTexture.SetMaterialUse(FbxFileTexture.eModelMaterial) lTexture.SetSwapUV(False) lTexture.SetTranslation(0.0, 0.0) lTexture.SetScale(1.0, 1.0) lTexture.SetRotation(0.0, 0.0) lMaterial.Ambient.ConnectSrcObject(lTexture) lTexture = FbxFileTexture.Create(pSdkManager,"Emissive Texture") lTexture.SetFileName("spotty.jpg") # Resource file is in current directory. lTexture.SetTextureUse(FbxTexture.eStandard) lTexture.SetMappingType(FbxTexture.eUV) lTexture.SetMaterialUse(FbxFileTexture.eModelMaterial) lTexture.SetSwapUV(False) lTexture.SetTranslation(0.0, 0.0) lTexture.SetScale(1.0, 1.0) lTexture.SetRotation(0.0, 0.0) lMaterial.Emissive.ConnectSrcObject(lTexture) def CreateCubeWithTexture(pSdkManager, pName): lMesh = FbxMesh.Create(pSdkManager,pName) lControlPoint0 = FbxVector4(-50, 0, 50) lControlPoint1 = FbxVector4(50, 0, 50) lControlPoint2 = FbxVector4(50, 100, 50) lControlPoint3 = FbxVector4(-50, 100, 50) lControlPoint4 = FbxVector4(-50, 0, -50) lControlPoint5 = FbxVector4(50, 0, -50) lControlPoint6 = FbxVector4(50, 100, -50) lControlPoint7 = FbxVector4(-50, 100, -50) lNormalXPos = FbxVector4(1, 0, 0) lNormalXNeg = FbxVector4(-1, 0, 0) lNormalYPos = FbxVector4(0, 1, 0) lNormalYNeg = FbxVector4(0, -1, 0) lNormalZPos = FbxVector4(0, 0, 1) lNormalZNeg = FbxVector4(0, 0, -1) lMesh.InitControlPoints(24) lMesh.SetControlPointAt(lControlPoint0, 0) lMesh.SetControlPointAt(lControlPoint1, 1) lMesh.SetControlPointAt(lControlPoint2, 2) lMesh.SetControlPointAt(lControlPoint3, 3) lMesh.SetControlPointAt(lControlPoint1, 4) lMesh.SetControlPointAt(lControlPoint5, 5) lMesh.SetControlPointAt(lControlPoint6, 6) lMesh.SetControlPointAt(lControlPoint2, 7) lMesh.SetControlPointAt(lControlPoint5, 8) lMesh.SetControlPointAt(lControlPoint4, 9) lMesh.SetControlPointAt(lControlPoint7, 10) lMesh.SetControlPointAt(lControlPoint6, 11) lMesh.SetControlPointAt(lControlPoint4, 12) lMesh.SetControlPointAt(lControlPoint0, 13) lMesh.SetControlPointAt(lControlPoint3, 14) lMesh.SetControlPointAt(lControlPoint7, 15) lMesh.SetControlPointAt(lControlPoint3, 16) lMesh.SetControlPointAt(lControlPoint2, 17) lMesh.SetControlPointAt(lControlPoint6, 18) lMesh.SetControlPointAt(lControlPoint7, 19) lMesh.SetControlPointAt(lControlPoint1, 20) lMesh.SetControlPointAt(lControlPoint0, 21) lMesh.SetControlPointAt(lControlPoint4, 22) lMesh.SetControlPointAt(lControlPoint5, 23) # Set the normals on Layer 0. lLayer = lMesh.GetLayer(0) if lLayer == None: lMesh.CreateLayer() lLayer = lMesh.GetLayer(0) # We want to have one normal for each vertex (or control point), # so we set the mapping mode to eByControlPoint. lLayerElementNormal= FbxLayerElementNormal.Create(lMesh, "") lLayerElementNormal.SetMappingMode(FbxLayerElement.eByControlPoint) # Here are two different ways to set the normal values. firstWayNormalCalculations = True if firstWayNormalCalculations: # The first method is to set the actual normal value # for every control point. lLayerElementNormal.SetReferenceMode(FbxLayerElement.eDirect) lLayerElementNormal.GetDirectArray().Add(lNormalZPos) lLayerElementNormal.GetDirectArray().Add(lNormalZPos) lLayerElementNormal.GetDirectArray().Add(lNormalZPos) lLayerElementNormal.GetDirectArray().Add(lNormalZPos) lLayerElementNormal.GetDirectArray().Add(lNormalXPos) lLayerElementNormal.GetDirectArray().Add(lNormalXPos) lLayerElementNormal.GetDirectArray().Add(lNormalXPos) lLayerElementNormal.GetDirectArray().Add(lNormalXPos) lLayerElementNormal.GetDirectArray().Add(lNormalZNeg) lLayerElementNormal.GetDirectArray().Add(lNormalZNeg) lLayerElementNormal.GetDirectArray().Add(lNormalZNeg) lLayerElementNormal.GetDirectArray().Add(lNormalZNeg) lLayerElementNormal.GetDirectArray().Add(lNormalXNeg) lLayerElementNormal.GetDirectArray().Add(lNormalXNeg) lLayerElementNormal.GetDirectArray().Add(lNormalXNeg) lLayerElementNormal.GetDirectArray().Add(lNormalXNeg) lLayerElementNormal.GetDirectArray().Add(lNormalYPos) lLayerElementNormal.GetDirectArray().Add(lNormalYPos) lLayerElementNormal.GetDirectArray().Add(lNormalYPos) lLayerElementNormal.GetDirectArray().Add(lNormalYPos) lLayerElementNormal.GetDirectArray().Add(lNormalYNeg) lLayerElementNormal.GetDirectArray().Add(lNormalYNeg) lLayerElementNormal.GetDirectArray().Add(lNormalYNeg) lLayerElementNormal.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. lLayerElementNormal.SetReferenceMode(FbxLayerElement.eIndexToDirect) # Add the 6 different normals to the direct array lLayerElementNormal.GetDirectArray().Add(lNormalZPos) lLayerElementNormal.GetDirectArray().Add(lNormalXPos) lLayerElementNormal.GetDirectArray().Add(lNormalZNeg) lLayerElementNormal.GetDirectArray().Add(lNormalXNeg) lLayerElementNormal.GetDirectArray().Add(lNormalYPos) lLayerElementNormal.GetDirectArray().Add(lNormalYNeg) # Now for each control point, we need to specify which normal to use lLayerElementNormal.GetIndexArray().Add(0) # index of lNormalZPos in the direct array. lLayerElementNormal.GetIndexArray().Add(0) # index of lNormalZPos in the direct array. lLayerElementNormal.GetIndexArray().Add(0) # index of lNormalZPos in the direct array. lLayerElementNormal.GetIndexArray().Add(0) # index of lNormalZPos in the direct array. lLayerElementNormal.GetIndexArray().Add(1) # index of lNormalXPos in the direct array. lLayerElementNormal.GetIndexArray().Add(1) # index of lNormalXPos in the direct array. lLayerElementNormal.GetIndexArray().Add(1) # index of lNormalXPos in the direct array. lLayerElementNormal.GetIndexArray().Add(1) # index of lNormalXPos in the direct array. lLayerElementNormal.GetIndexArray().Add(2) # index of lNormalZNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(2) # index of lNormalZNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(2) # index of lNormalZNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(2) # index of lNormalZNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(3) # index of lNormalXNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(3) # index of lNormalXNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(3) # index of lNormalXNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(3) # index of lNormalXNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(4) # index of lNormalYPos in the direct array. lLayerElementNormal.GetIndexArray().Add(4) # index of lNormalYPos in the direct array. lLayerElementNormal.GetIndexArray().Add(4) # index of lNormalYPos in the direct array. lLayerElementNormal.GetIndexArray().Add(4) # index of lNormalYPos in the direct array. lLayerElementNormal.GetIndexArray().Add(5) # index of lNormalYNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(5) # index of lNormalYNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(5) # index of lNormalYNeg in the direct array. lLayerElementNormal.GetIndexArray().Add(5) # index of lNormalYNeg in the direct array. lLayer.SetNormals(lLayerElementNormal) # Array of polygon vertices. 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 ) # Set texture mapping for diffuse channel. lTextureDiffuseLayer=FbxLayerElementTexture.Create(lMesh, "Diffuse Texture") lTextureDiffuseLayer.SetMappingMode(FbxLayerElement.eByPolygon) lTextureDiffuseLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetTextures(FbxLayerElement.eTextureDiffuse, lTextureDiffuseLayer) # Set texture mapping for ambient channel. lTextureAmbientLayer=FbxLayerElementTexture.Create(lMesh, "Ambient Textures") lTextureAmbientLayer.SetMappingMode(FbxLayerElement.eByPolygon) lTextureAmbientLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetTextures(FbxLayerElement.eTextureAmbient, lTextureAmbientLayer) # Set texture mapping for emissive channel. lTextureEmissiveLayer=FbxLayerElementTexture.Create(lMesh, "Emissive Textures") lTextureEmissiveLayer.SetMappingMode(FbxLayerElement.eByPolygon) lTextureEmissiveLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetTextures(FbxLayerElement.eTextureEmissive, lTextureEmissiveLayer) # Create UV for Diffuse channel lUVDiffuseLayer = FbxLayerElementUV.Create(lMesh, "DiffuseUV") lUVDiffuseLayer.SetMappingMode(FbxLayerElement.eByPolygonVertex) lUVDiffuseLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetUVs(lUVDiffuseLayer, FbxLayerElement.eTextureDiffuse) lVectors0 = FbxVector2(0, 0) lVectors1 = FbxVector2(1, 0) lVectors2 = FbxVector2(1, 1) lVectors3 = FbxVector2(0, 1) lUVDiffuseLayer.GetDirectArray().Add(lVectors0) lUVDiffuseLayer.GetDirectArray().Add(lVectors1) lUVDiffuseLayer.GetDirectArray().Add(lVectors2) lUVDiffuseLayer.GetDirectArray().Add(lVectors3) # Create UV for Ambient channel lUVAmbientLayer=FbxLayerElementUV.Create(lMesh, "AmbientUV") lUVAmbientLayer.SetMappingMode(FbxLayerElement.eByPolygonVertex) lUVAmbientLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetUVs(lUVAmbientLayer, FbxLayerElement.eTextureAmbient) lVectors0.Set(0, 0) lVectors1.Set(1, 0) lVectors2.Set(0, 0.418586879968643) lVectors3.Set(1, 0.418586879968643) lUVAmbientLayer.GetDirectArray().Add(lVectors0) lUVAmbientLayer.GetDirectArray().Add(lVectors1) lUVAmbientLayer.GetDirectArray().Add(lVectors2) lUVAmbientLayer.GetDirectArray().Add(lVectors3) # Create UV for Emissive channel lUVEmissiveLayer=FbxLayerElementUV.Create(lMesh, "EmissiveUV") lUVEmissiveLayer.SetMappingMode(FbxLayerElement.eByPolygonVertex) lUVEmissiveLayer.SetReferenceMode(FbxLayerElement.eIndexToDirect) lLayer.SetUVs(lUVEmissiveLayer, FbxLayerElement.eTextureEmissive) lVectors0.Set(0.2343, 0) lVectors1.Set(1, 0.555) lVectors2.Set(0.333, 0.999) lVectors3.Set(0.555, 0.666) lUVEmissiveLayer.GetDirectArray().Add(lVectors0) lUVEmissiveLayer.GetDirectArray().Add(lVectors1) lUVEmissiveLayer.GetDirectArray().Add(lVectors2) lUVEmissiveLayer.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. lUVDiffuseLayer.GetIndexArray().SetCount(24) lUVEmissiveLayer.GetIndexArray().SetCount(24) lUVAmbientLayer.GetIndexArray().SetCount(24) #in the same way we with Textures, but we are in eBY_POLYGON and as we are doing a cube, #we should have 6 polygons (1 for each faces of the cube) lTextureDiffuseLayer.GetIndexArray().SetCount(6) lTextureAmbientLayer.GetIndexArray().SetCount(6) lTextureEmissiveLayer.GetIndexArray().SetCount(6) # Create polygons. Assign texture and texture UV indices. for i in range(6): #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) #Here we set the the index array for each channel lTextureDiffuseLayer.GetIndexArray().SetAt(i,0) lTextureAmbientLayer.GetIndexArray().SetAt(i,0) lTextureEmissiveLayer.GetIndexArray().SetAt(i,0) for j in range(4): #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 lUVDiffuseLayer.GetIndexArray().SetAt(i*4+j, j) lUVAmbientLayer.GetIndexArray().SetAt(i*4+j, j) lUVEmissiveLayer.GetIndexArray().SetAt(i*4+j, j) lMesh.EndPolygon() lNode = FbxNode.Create(pSdkManager,pName) lNode.SetNodeAttribute(lMesh) lNode.SetShadingMode(FbxNode.eTextureShading) CreateTexture(pSdkManager, lMesh) return lNode def SetCubeDefaultPosition(pCube): pCube.LclTranslation.Set(FbxDouble3(-75.0, -50.0, 0.0)) pCube.LclRotation.Set(FbxDouble3(0.0, 0.0, 0.0)) pCube.LclScaling.Set(FbxDouble3(1.0, 1.0, 1.0)) def CreateScene(pSdkManager, pScene, pSampleFileName): lCube = CreateCubeWithTexture(pSdkManager, "Cube") SetCubeDefaultPosition(lCube) lRootNode = pScene.GetRootNode() lRootNode.AddChild(lCube) def main(): lSampleFileName = "D:/user/houdini/createBoxFbx.fbx" (lSdkManager, lScene) = FbxCommon.InitializeSdkObjects() lResult = CreateScene(lSdkManager, lScene, lSampleFileName) lResult = FbxCommon.SaveScene(lSdkManager, lScene, lSampleFileName) lSdkManager.Destroy() main()