def setNodeTransforms(self, node, prim): t = fbx.FbxVector4(node.LclTranslation.Get()) ro = node.GetRotationOffset(fbx.FbxNode.eSourcePivot) rp = node.GetRotationPivot(fbx.FbxNode.eSourcePivot) preRotation = node.GetPreRotation(fbx.FbxNode.eSourcePivot) r = fbx.FbxVector4(node.LclRotation.Get()) postRotation = node.GetPostRotation(fbx.FbxNode.eSourcePivot) so = node.GetScalingOffset(fbx.FbxNode.eSourcePivot) sp = node.GetScalingPivot(fbx.FbxNode.eSourcePivot) s = fbx.FbxVector4(node.LclScaling.Get()) # set translation self.addTranslateOpIfNotEmpty(prim, t) # set rotation offset, pivot and pre-post rotation ops self.addTranslateOpIfNotEmpty(prim, ro, "rotationOffset") self.addTranslateOpIfNotEmpty(prim, rp, "rotationPivot") self.addRotationOpIfNotEmpty(prim, preRotation, "preRotation") self.addRotationOpIfNotEmpty(prim, r) self.addRotationOpIfNotEmpty(prim, postRotation, "postRotation") self.addInvertTranslateOpIfNotEmpty(prim, -rp, "rotationPivot") # set scaling offset & pivot self.addTranslateOpIfNotEmpty(prim, so, "scalingOffset") self.addTranslateOpIfNotEmpty(prim, sp, "scalingPivot") self.addScalingOpIfNotEmpty(prim, s) self.addInvertTranslateOpIfNotEmpty(prim, -rp, "scalingPivot")
def CreateTriangle(pSdkManager, pName): lMesh = fbx.FbxMesh.Create(pSdkManager, pName) # The three vertices lControlPoint0 = fbx.FbxVector4(0.1, 0, 0) lControlPoint1 = fbx.FbxVector4(0, 0.1, 0) lControlPoint2 = fbx.FbxVector4(0, 0, 0.1) # Create control points. lMesh.InitControlPoints(3) lMesh.SetControlPointAt(lControlPoint0, 0) lMesh.SetControlPointAt(lControlPoint1, 1) lMesh.SetControlPointAt(lControlPoint2, 2) # Create the triangle's polygon lMesh.BeginPolygon() lMesh.AddPolygon(0) # Control point 0 lMesh.AddPolygon(1) # Control point 1 lMesh.AddPolygon(2) # Control point 2 lMesh.EndPolygon() lNode = fbx.FbxNode.Create(pSdkManager, pName) lNode.SetNodeAttribute(lMesh) return lNode
def hasGeometricTransform(self, fbxNode): if (fbx.FbxVector4(0, 0, 0, 1) != fbxNode.GetGeometricTranslation( fbx.FbxNode.eSourcePivot) or fbx.FbxVector4(0, 0, 0, 1) != fbxNode.GetGeometricRotation(fbx.FbxNode.eSourcePivot) or fbx.FbxVector4(1, 1, 1, 1) != fbxNode.GetGeometricScaling( fbx.FbxNode.eSourcePivot)): return True return False
def sceneBounds(self, precision=3): min = fbx.FbxVector4() max = fbx.FbxVector4() center = fbx.FbxVector4() self._scene.ComputeBoundingBoxMinMaxCenter(min, max, center) x = round(max[0] - min[0], precision) y = round(max[1] - min[1], precision) z = round(max[2] - min[2], precision) return x, y, z
def addScalingOpIfNotEmpty(self, prim, op, name='', idScaling=None): if idScaling is None: idScaling = fbx.FbxVector4(1, 1, 1, 1) if op != idScaling: prim.AddScaleOp(UsdGeom.XformOp.PrecisionFloat, name).Set( (op[0], op[1], op[2]))
def addRotationOpIfNotEmpty(self, prim, op, name='', idRotation=None): if idRotation is None: idRotation = fbx.FbxVector4(0, 0, 0, 1) if op != idRotation: prim.AddRotateXYZOp(UsdGeom.XformOp.PrecisionFloat, name).Set( (op[0], op[1], op[2]))
def load_mesh(mesh): controlPointsCount = mesh.GetControlPointsCount() controlPoints = mesh.GetControlPoints() uv = get_uv_set(mesh) vertices = [] indices = [] for i in range(0, mesh.GetPolygonCount()): polygonSize = mesh.GetPolygonSize(i) assert polygonSize == 3 for j in range(0, polygonSize): controlPointIndex = mesh.GetPolygonVertex(i, j) if controlPointIndex > controlPointsCount: continue uv0 = fbx.FbxVector2() uv1 = fbx.FbxVector2() normal = fbx.FbxVector4() pos = controlPoints[controlPointIndex] mesh.GetPolygonVertexNormal(i, j, normal) mesh.GetPolygonVertexUV(i, j, uv[0], uv0) if len(uv) > 1: mesh.GetPolygonVertexUV(i, j, uv[1], uv1) vertices.append(Vertex(pos, normal, uv0, uv1)) indices.append(len(vertices) - 1) load_mesh.chunks.append(convert_fbx.chunk(vertices=vertices, indices=indices))
def CreateNurbs(pSdkManager, pName): lNurbs = fbx.FbxNurbs.Create(pSdkManager, pName) lNurbs.SetOrder(4, 4) lNurbs.SetStep(2, 2) lNurbs.InitControlPoints(6, fbx.FbxNurbs.ePeriodic, 7, fbx.FbxNurbs.eOpen) lNurbs.SetUKnotVector(list(UKnotVector)) lNurbs.SetVKnotVector(list(VKnotVector)) lScale = 20.0 lPi = 3.14159 lYAngle = (90.0, 90.0, 52.0, 0.0, -52.0, -90.0, -90.0) lRadius = (0.0, 0.283, 0.872, 1.226, 0.872, 0.283, 0.0) for i in range(7): for j in range(6): lX = lScale * lRadius[i] * math.cos(lPi / 4 * j) lY = lScale * math.sin(2 * lPi / 360 * lYAngle[i]) lZ = lScale * lRadius[i] * math.sin(lPi / 4 * j) lNurbs.SetControlPointAt(fbx.FbxVector4(lX, lY, lZ, 1.0), 8 * i + j) # Create Layer 0 where material and texture will be applied if not lNurbs.GetLayer(0): lNurbs.CreateLayer() lNurbsNode = fbx.FbxNode.Create(pSdkManager, pName) lNurbsNode.SetNodeAttribute(lNurbs) return lNurbsNode
def euler_angle_to_quaternions(x, y, z): transform = fbx.FbxAMatrix() transform.SetIdentity() transform.SetR(fbx.FbxVector4( x, y, z, 0.0)) # euler angle is 'eEulerXYZ' here, i.e. apply Z first q = transform.GetQ() return q
def set_rotation_pivot(self, coordinate): self.pyramid_node.SetRotationActive(True) x = float(coordinate[0]) y = float(coordinate[1]) z = float(coordinate[2]) self.pyramid_node.SetRotationPivot(fbx.FbxNode.eSourcePivot, fbx.FbxVector4(x, y, z))
def __add_2d_line_mesh(self, start, end, thickness, color): direction = (end - start) direction.Normalize() right_vector = fbx.FbxVector4(-direction[1], direction[0], direction[3]) bottom_left_vertex = (start - right_vector * thickness) bottom_right_vertex = (start + right_vector * thickness) top_left_vertex = (end - right_vector * thickness) top_right_vertex = (end + right_vector * thickness) self.__create_mesh(bottom_left_vertex, bottom_right_vertex, top_left_vertex, top_right_vertex)
def thingB1(): """ Create locator, give it some random local rotate values. Get matrix via xform. Decompose matrix to local rotate values. Compare values """ # initialize a random rotation rotate = get_random_rotate(ROTATE_SEED) # create a locator and apply rotation loc = cmds.spaceLocator()[0] cmds.xform(loc, rotation=rotate) # query local matrix local_matrix = cmds.getAttr(loc + ".matrix") # seperate rows row_0 = local_matrix[0:4] row_1 = local_matrix[4:8] row_2 = local_matrix[8:12] row_3 = local_matrix[12:16] # apply matrix to new loc to compare how maya xform command performs # loc_1 = cmds.spaceLocator()[0] loc_1 = cmds.createNode("transform") cmds.xform(loc_1, matrix=local_matrix) maya_decomp = cmds.xform(loc_1, query=True, rotation=True) # construct fbx matrix fbx_matrix = fbx.FbxMatrix() for i, row in enumerate([row_0, row_1, row_2, row_3]): fbx_matrix.SetRow(i, fbx.FbxVector4(*row)) # decompose via FbxMatrix, FbxQuaternion and FbxAMatrix # note this only works for XYZ rotation order pTranslation = fbx.FbxVector4() pRotation = fbx.FbxQuaternion() pShearing = fbx.FbxVector4() pScaling = fbx.FbxVector4() fbx_matrix.GetElements( pTranslation, pRotation, pShearing, pScaling, ) test = fbx.FbxAMatrix() test.SetQ(pRotation) # manual decomp # nope try again (wrong order? xyz instead of zyx?) #rot_y = math.asin(row_2[0]) # xyz order gives correct y # interesting to note sometimes this matches maya decomp # and sometimes is matches original rotation rot_y = -math.asin(row_0[2]) rot_y_degs = math.degrees(rot_y) # not exactly # correct value but positive/negative often incorrect # not sure why # rot_x = math.acos(row_2[2] / math.cos(rot_y)) # rot_x_degs = math.degrees(rot_x) # rot_x = math.asin(row_1[2] / math.cos(rot_y)) # rot_x_degs = math.degrees(rot_x) # # rot_z = math.acos(row_0[0] / math.cos(rot_y)) # rot_z_degs = math.degrees(rot_z) # use sine instead of cosine to get pos/neg values # sometimes right!! # obviously there's certain conditions where this works # and others where it doesn't # probably some gimbal lock related stuff # TODO rot y seems to be correct 100% of the time # do some random tests to see if that's consistent # _p for partial # rot_x_p = math.asin(row_2[2] / math.sin(math.radians(90 - rot_y_degs))) # rot_x_degs = (math.degrees(rot_x_p) - 90) * -1 # # rot_z = math.asin(row_0[1] / math.sin(math.radians(90 - rot_y_degs))) # rot_z_degs = math.degrees(rot_z) # check for pos/neg # we can determine the direction of rotation by comparing # cosine and sine values of the angle # these can be found from particular rows and columns # of the matrix when written out algebraically # this seems to work consistently!!! sin_z = row_0[1] / math.cos(rot_y) cos_z = row_0[0] / math.cos(rot_y) print "cos z: {}, sin z: {}".format(cos_z, sin_z) if cos_z == 1: rot_z = 0.0 elif cos_z == 0: rot_z = math.radians(180) elif sin_z == 1: rot_z = math.radians(90) elif sin_z == -1: rot_z = math.radians(-90) elif cos_z > 0 and sin_z > 0: print "+z" rot_z = math.acos(cos_z) elif cos_z < 0 and sin_z > 0: print "180-z" rot_z = math.radians(180) - math.asin(sin_z) elif cos_z > 0 and sin_z < 0: print "-z" rot_z = -math.acos(cos_z) elif cos_z < 0 and sin_z < 0: print "-180-z" rot_z = math.radians(-180) - math.asin(sin_z) elif cos_z > 1 or cos_z < -1 or sin_z > 1 or sin_z < -1: raise Exception("-1 > cos/sin > 1 out of bounds") # TOOD if neccesary rot_z_degs = math.degrees(rot_z) # check for pos/neg cos_x = row_2[2] / math.cos(rot_y) sin_x = row_1[2] / math.cos(rot_y) print "cos x: {}, sin x: {}".format(cos_x, sin_x) if cos_x == 1: rot_x = 0.0 elif cos_x == 0: rot_x = math.radians(180) elif sin_x == 1: rot_x = math.radians(90) elif sin_x == -1: rot_x = math.radians(-90) elif cos_x > 0 and sin_x > 0: print "+z" rot_x = math.acos(cos_x) elif cos_x < 0 and sin_x > 0: print "180-z" rot_x = math.radians(180) - math.asin(sin_x) elif cos_x > 0 and sin_x < 0: print "-z" rot_x = -math.acos(cos_x) elif cos_x < 0 and sin_x < 0: print "-180-z" rot_x = math.radians(-180) - math.asin(sin_x) elif cos_x > 1 or cos_x < -1 or sin_x > 1 or sin_x < -1: raise Exception("-1 > cos/sin > 1 out of bounds") # TOOD if neccesary rot_x_degs = math.degrees(rot_x) # test going back through each rotation # Nope, can't work cos y is not the last rotation! # mat_y = fbx.FbxMatrix() # mat_y.SetRow(0, fbx.FbxVector4(math.cos(rot_y), 0, -math.sin(rot_y), 0)) # mat_y.SetRow(1, fbx.FbxVector4(0, 1, 0, 0)) # mat_y.SetRow(2, fbx.FbxVector4(math.sin(rot_y), 0, math.cos(rot_y), 0)) # mat_y.SetRow(3, fbx.FbxVector4(0, 0, 0, 1)) # # mat_xz = mat_y.Inverse() * fbx_matrix # # rot_x = math.acos(mat_xz.GetRow(1)[1]) # rot_x_degs = math.degrees(rot_x) # # rot_z_degs = 0 # TODO # test manual decomp loc_2 = cmds.spaceLocator()[0] cmds.xform(loc_2, rotation=(rot_x_degs, rot_y_degs, rot_z_degs)) # test scipy direction cosines method # get direction cosines using dot product # this seems to suffer similar problems # to when we don't check for pos/neg rotations # sometimes is correct, others not # probably best to avoid using this # especially considering this module # is not present in the sourced maya version of scipy world_x_vec = fbx.FbxVector4(1, 0, 0) world_y_vec = fbx.FbxVector4(0, 1, 0) world_z_vec = fbx.FbxVector4(0, 0, 1) world_vectors = [world_x_vec, world_y_vec, world_z_vec] row_0_vec = fbx.FbxVector4(*row_0) row_1_vec = fbx.FbxVector4(*row_1) row_2_vec = fbx.FbxVector4(*row_2) row_vectors = [fbx.FbxVector4(*i) for i in row_0, row_1, row_2] # actually, we can determine if these should be positive or negative # from cross products etc. # would that actually help though?? # TODO! direction_cosines = [ [row_vec.DotProduct(w_vec) for w_vec in world_vectors] for row_vec in row_vectors ] sp_rot = scipy_rotation.from_dcm( numpy.array(direction_cosines) ) sp_decomp = sp_rot.as_euler('XYZ', degrees=True) # loc_3 = cmds.spaceLocator()[0] # cmds.xform(loc_3, rotation=sp_decomp.tolist()) # compare matrices print "maya matrix attr: ", local_matrix fbx_matrix_list = [j for i in range(4) for j in list(fbx_matrix.GetRow(i))] print "fbx matrix: ", fbx_matrix_list # print rows print "maya matrix rows:\n\t{}\n\t{}\n\t{}\n\t{}".format( row_0, row_1, row_2, row_3 ) # compare results print "rotation: ", rotate print "maya decomp: ", maya_decomp print "Fbx decomp: {}".format(list(test.GetR())) print "Scipy decomp: {}".format(sp_decomp.tolist()) print "manual decomp: ", rot_x_degs, rot_y_degs, rot_z_degs
def addTranslateOpIfNotEmpty(self, prim, op, name=''): if op != fbx.FbxVector4(0, 0, 0, 1): prim.AddTranslateOp(UsdGeom.XformOp.PrecisionFloat, name).Set( (op[0], op[1], op[2]))
def __coords_to_vertex4(self, coords): fbx_list = [ fbx.FbxVector4(coord[1], coord[0], self.__pos_Z, 1) for coord in coords ] return fbx_list
import fbx # A set of vertices which we will use to create a cube in the scene. cubeVertices = [ fbx.FbxVector4(-5, -5, 5), # 0 - vertex index. fbx.FbxVector4(5, -5, 5), # 1 fbx.FbxVector4(5, 5, 5), # 2 fbx.FbxVector4(-5, 5, 5), # 3 fbx.FbxVector4(-5, -5, -5), # 4 fbx.FbxVector4(5, -5, -5), # 5 fbx.FbxVector4(5, 5, -5), # 6 fbx.FbxVector4(-5, 5, -5) ] # 7 # The polygons (faces) of the cube. polygonVertices = [ (0, 1, 2, 3), # Face 1 - composed of the vertex index sequence: 0, 1, 2, and 3. (4, 5, 6, 7), # Face 2 (8, 9, 10, 11), # Face 3 (12, 13, 14, 15), # Face 4 (16, 17, 18, 19), # Face 5 (20, 21, 22, 23) ] # Face 6 saveFilename = 'myFbxSaveFile.fbx' ############################################################### # Helper Function(s). # ###############################################################
def addInvertTranslateOpIfNotEmpty(self, prim, op, name=''): if op != fbx.FbxVector4(0, 0, 0, -1): prim.AddTranslateOp(UsdGeom.XformOp.PrecisionFloat, name, True)
def create_fbx(fbx_path, polygons, verticies): # Create the required FBX SDK data structures. fbx_manager = fbx.FbxManager.Create() fbx_scene = fbx.FbxScene.Create(fbx_manager, '') mdl_name = os.path.basename(fbx_path) scene_info = fbx.FbxDocumentInfo.Create(fbx_manager, "SceneInfo") scene_info.mTitle = mdl_name scene_info.mSubject = "Another SMD converter thingy..." scene_info.mAuthor = "iDGi" scene_info.mRevision = "rev. 1.0" scene_info.mKeywords = mdl_name scene_info.mComment = "n/a" fbx_scene.SetSceneInfo(scene_info) root_node = fbx_scene.GetRootNode() # add the model node, we will put all the verts and stuff in that mdl_node = fbx.FbxNode.Create(fbx_scene, mdl_name) root_node.AddChild(mdl_node) # create new node for the mesh new_node = fbx.FbxNode.Create(fbx_scene, '{0}Node{1}'.format(mdl_name, 0)) mdl_node.AddChild(new_node) new_mesh = fbx.FbxMesh.Create(fbx_scene, '{0}Mesh{1}'.format(mdl_name, 0)) new_node.SetNodeAttribute(new_mesh) new_node.SetShadingMode(fbx.FbxNode.eTextureShading) # Init the required number of control points (verticies) new_mesh.InitControlPoints(len(verticies)) # Add all the verticies for this group for i in range(0, len(verticies)): vertex = verticies[i] new_mesh.SetControlPointAt( fbx.FbxVector4(vertex.vert.x, vertex.vert.y, vertex.vert.z), i) # Create the layer to store UV and normal data layer = new_mesh.GetLayer(0) if not layer: new_mesh.CreateLayer() layer = new_mesh.GetLayer(0) # Create the materials. # Each polygon face will be assigned a unique material. # matLayer = fbx.FbxLayerElementMaterial.Create(new_mesh, "") # matLayer.SetMappingMode(fbx.FbxLayerElement.eByPolygon) # matLayer.SetReferenceMode(fbx.FbxLayerElement.eIndexToDirect) # layer.SetMaterials(matLayer) # Setup the indicies (the connections between verticies) per polygon for i in range(0, len(polygons)): new_mesh.BeginPolygon(i) polygon = polygons[i] for j in range(0, 3): new_mesh.AddPolygon(polygon.indicies[j]) new_mesh.EndPolygon() # create the UV textures mapping. # On layer 0 all the faces have the same texture uvLayer = fbx.FbxLayerElementUV.Create(new_mesh, '') uvLayer.SetMappingMode(fbx.FbxLayerElement.eByPolygonVertex) uvLayer.SetReferenceMode(fbx.FbxLayerElement.eDirect) # # For all the verticies, set the UVs for i in range(0, len(polygons)): polygon = polygons[i] for j in range(0, 3): uvLayer.GetDirectArray().Add( fbx.FbxVector2(polygon.uvs[j].x, polygon.uvs[j].y)) layer.SetUVs(uvLayer) # specify normals per control point. # For compatibility, we follow the rules stated in the # layer class documentation: normals are defined on layer 0 and # are assigned by control point. normLayer = fbx.FbxLayerElementNormal.Create(new_mesh, '') normLayer.SetMappingMode( fbx.FbxLayerElement.eByPolygonVertex) # eByControlPoint normLayer.SetReferenceMode(fbx.FbxLayerElement.eDirect) for i in range(0, len(polygons)): polygon = polygons[i] for j in range(0, 3): normLayer.GetDirectArray().Add( fbx.FbxVector4(polygon.normals[j].x, polygon.normals[j].y, polygon.normals[j].z, 1.0)) # for i in range(0, len(verticies)): # vertex = verticies[i] # normLayer.GetDirectArray().Add(fbx.FbxVector4(vertex.normal.x, vertex.normal.y, vertex.normal.z, 1.0)) layer.SetNormals(normLayer) # Set textures texture_name = polygons[0].texture # Create texture if nessesary texture = create_texture(fbx_manager, texture_name, texture_name) # We also need a material, create that now material_name = fbx.FbxString(texture_name) material = fbx.FbxSurfacePhong.Create(fbx_manager, material_name.Buffer()) # Generate primary and secondary colors. material.Emissive.Set(fbx.FbxDouble3(0.0, 0.0, 0.0)) material.Ambient.Set(fbx.FbxDouble3(1.0, 1.0, 1.0)) material.Diffuse.Set(fbx.FbxDouble3(1.0, 1.0, 1.0)) material.Specular.Set(fbx.FbxDouble3(0.0, 0.0, 0.0)) material.TransparencyFactor.Set(0.0) material.Shininess.Set(0.5) material.ShadingModel.Set(fbx.FbxString("phong")) material_info = (material, texture) texLayer = fbx.FbxLayerElementTexture.Create(new_mesh, '') texLayer.SetBlendMode(fbx.FbxLayerElementTexture.eModulate) texLayer.SetMappingMode(fbx.FbxLayerElement.eByPolygon) texLayer.SetReferenceMode(fbx.FbxLayerElement.eIndexToDirect) texLayer.GetDirectArray().Add(material_info[1]) # set all faces to that texture for i in range(0, len(polygons)): texLayer.GetIndexArray().Add(0) layer.SetTextures(fbx.FbxLayerElement.eTextureDiffuse, texLayer) new_node.AddMaterial(material_info[0]) # Save the scene. save_scene(fbx_path, fbx_manager, fbx_scene, False) # Destroy the fbx manager explicitly, which recursively destroys # all the objects that have been created with it. fbx_manager.Destroy() del fbx_manager, fbx_scene
def set_post_rotation(self, coordinate): x = float(coordinate[0]) y = float(coordinate[1]) z = float(coordinate[2]) self.pyramid_node.SetPostRotation(fbx.FbxNode.eSourcePivot, fbx.FbxVector4(x, y, z))
def create(self, base_width, height): self.base_width = base_width self.height = height pyramid = fbx.FbxMesh.Create(self.scene, self.name) # Calculate the vertices of the pyramid lying down base_width_half = base_width / 2 controlpoints = [ fbx.FbxVector4(0, height, 0), fbx.FbxVector4(base_width_half, 0, base_width_half), fbx.FbxVector4(base_width_half, 0, -base_width_half), fbx.FbxVector4(-base_width_half, 0, -base_width_half), fbx.FbxVector4(-base_width_half, 0, base_width_half) ] # Initialize and set the control points of the mesh controlpoint_count = len(controlpoints) pyramid.InitControlPoints(controlpoint_count) for i, p in enumerate(controlpoints): pyramid.SetControlPointAt(p, i) # Set the control point indices of the bottom plane of the pyramid pyramid.BeginPolygon() pyramid.AddPolygon(1) pyramid.AddPolygon(4) pyramid.AddPolygon(3) pyramid.AddPolygon(2) pyramid.EndPolygon() # Set the control point indices of the front plane of the pyramid pyramid.BeginPolygon() pyramid.AddPolygon(0) pyramid.AddPolygon(1) pyramid.AddPolygon(2) pyramid.EndPolygon() # Set the control point indices of the left plane of the pyramid pyramid.BeginPolygon() pyramid.AddPolygon(0) pyramid.AddPolygon(2) pyramid.AddPolygon(3) pyramid.EndPolygon() # Set the control point indices of the back plane of the pyramid pyramid.BeginPolygon() pyramid.AddPolygon(0) pyramid.AddPolygon(3) pyramid.AddPolygon(4) pyramid.EndPolygon() # Set the control point indices of the right plane of the pyramid pyramid.BeginPolygon() pyramid.AddPolygon(0) pyramid.AddPolygon(4) pyramid.AddPolygon(1) pyramid.EndPolygon() # Attach the mesh to a node pyramid_node = fbx.FbxNode.Create(self.scene, '') pyramid_node.SetNodeAttribute(pyramid) self.pyramid_node = pyramid_node return pyramid_node
def create_nurbs_curve(): """Create nurbs curve example. https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_nurbs_curve_html """ fbx_manager = fbx.FbxManager.Create() fbx_scene = fbx.FbxScene.Create(fbx_manager, "TestScene") # create curve M = 4 # degree/order N = 10 # number of control points crv_node = fbx.FbxNode.Create(fbx_manager, "test_curve") crv_attr = fbx.FbxNurbsCurve.Create(fbx_manager, "") crv_node.SetNodeAttribute(crv_attr) pOrder = M # crv_attr.SetStep(16) crv_attr.SetOrder(pOrder) pCount = N pVType = fbx.FbxNurbsCurve.eOpen # pVType = fbx.FbxNurbsCurve.ePeriodic crv_attr.InitControlPoints(pCount, pVType) # crv_attr.InitTangents() # crv_attr.InitNormals() # crv_attr.SetDimension(fbx.FbxNurbsCurve.e3D) # or e2D # modify curve for i in range(N): crv_attr.SetControlPointAt(fbx.FbxVector4(i, 0.0, 50.0, 1.0), i) print crv_attr.IsRational() points = crv_attr.GetControlPoints() for point in points: print point # for i in range(4, N - 4): # crv_attr.SetControlPointAt( # fbx.FbxVector4(i, 0.0, 50.0, 0.0), # i # ) # # for i in range(N - 4, N): # crv_attr.SetControlPointAt( # fbx.FbxVector4(N - 4, 0.0, 50.0, 0.0), # i # ) # # crv_attr.SetControlPointNormalAt( # fbx.FbxVector4(1.0, 1.0, 1.0, 1.0), # i # ) # # for i in dir(crv_attr): # print i knots_a = crv_attr.GetKnotVector() knots_b = crv_attr.GetKnotVector() print knots_a print knots_a == knots_b print knots_a is knots_b # crv_attr.SetKnotVector() # evaluate curve # crv_line = crv_attr.TessellateCurve(16) # print help(crv_attr.ConvertDirectToIndexToDirect) # print help(crv_attr.Localize) # add curve to scene fbx_scene.GetRootNode().AddChild(crv_node) # save file using FbxCommon res = FbxCommon.SaveScene(fbx_manager, fbx_scene, TEST_EXPORT_FILE)
def thingA1(): """ Create locator, give it some random local translate and rotate values. Get matrix via xform. Calculate matrix manually. Compare matrices. xform second locator with manual matrix. Compare locators. """ loc = cmds.spaceLocator()[0] rotate = get_random_rotate(ROTATE_SEED) print "rotation: ", rotate rads = [math.radians(i) for i in rotate] print "radians: ", rads cmds.xform(loc, rotation=rotate) xform_matrix = cmds.xform(loc, query=True, matrix=True) print "maya xform: ", xform_matrix local_matrix = cmds.getAttr(loc + ".matrix") print "maya matrix attr: ", local_matrix x_rot, y_rot, z_rot = rads x_matrix = [ [1.0, 0.0, 0.0, 0.0], [0.0, math.cos(x_rot), math.sin(x_rot), 0.0], [0.0, -math.sin(x_rot), math.cos(x_rot), 0.0], [0.0, 0.0, 0.0, 1.0] ] y_matrix = [ [math.cos(y_rot), 0.0, -math.sin(y_rot), 0.0], [0.0, 1.0, 0.0, 0.0], [math.sin(y_rot), 0.0, math.cos(y_rot), 0.0], [0.0, 0.0, 0.0, 1.0] ] z_matrix = [ [math.cos(z_rot), math.sin(z_rot), 0.0, 0.0], [-math.sin(z_rot), math.cos(z_rot), 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0] ] fbx_x_matrix = fbx.FbxMatrix() for i, row in enumerate(x_matrix): fbx_x_matrix.SetRow(i, fbx.FbxVector4(*row)) fbx_y_matrix = fbx.FbxMatrix() for i, row in enumerate(y_matrix): fbx_y_matrix.SetRow(i, fbx.FbxVector4(*row)) fbx_z_matrix = fbx.FbxMatrix() for i, row in enumerate(z_matrix): fbx_z_matrix.SetRow(i, fbx.FbxVector4(*row)) transform = fbx_z_matrix * fbx_y_matrix * fbx_x_matrix # print matrix fbx_matrix = [j for i in range(4) for j in list(transform.GetRow(i))] print "fbx matrix: ", fbx_matrix # test on new loc loc2 = cmds.spaceLocator()[0] cmds.xform(loc2, matrix=fbx_matrix) # interesting to note that maya does not decompose # identical local rotate values to the original # loc2 and loc3 results are the same # axes align with loc1, but local values are different! loc3 = cmds.spaceLocator()[0] cmds.xform(loc3, matrix=local_matrix) # decompose via FbxMatrix, FbxQuaternion and FbxAMatrix # note this only works for XYZ rotation order pTranslation = fbx.FbxVector4() pRotation = fbx.FbxQuaternion() pShearing = fbx.FbxVector4() pScaling = fbx.FbxVector4() transform.GetElements( pTranslation, pRotation, pShearing, pScaling, ) # test results # local values are same as maya's decompose! # as in correct axis alignment with loc1 # but different local values to loc1 test = fbx.FbxAMatrix() test.SetQ(pRotation) print "FbxAMatrix rotation: ", test.GetR()
def create_mesh_controlpoint(self, x, y, z): """Create a mesh controlpoint.""" self.mesh.SetControlPointAt(fbx.FbxVector4(x, y, z), FBox.cpt_count) FBox.cpt_count += 1
def makeMesh(pScene, pMaterial, mesh, texture=None): result = fbx.FbxMesh.Create(pScene, mesh.name + "_Mesh") result.InitControlPoints(len(mesh.vertices)) index = 0 for v in mesh.vertices: v4 = fbx.FbxVector4(v.x, v.y, v.z, 0.0) result.SetControlPointAt(v4, index) index = index + 1 index = 0 for f in mesh.faces: result.BeginPolygon(index) vi0 = mesh.edges[mesh.faces[index].e0].v0 vi1 = mesh.edges[mesh.faces[index].e1].v0 vi2 = mesh.edges[mesh.faces[index].e2].v0 result.AddPolygon(vi0) result.AddPolygon(vi1) result.AddPolygon(vi2) result.EndPolygon() index = index + 1 # generate a normal layer result.GenerateNormals() # add a layer with uvs and colors layer = result.GetLayer(0) if (not layer): result.CreaterLayer() layer = mesh.GetLayer(0) # color layer if (mesh.has_colors()): colorLayerElement = fbx.FbxLayerElementVertexColor.Create(result, "") colorLayerElement.SetMappingMode(fbx.FbxLayerElement.eByControlPoint) colorLayerElement.SetReferenceMode(fbx.FbxLayerElement.eDirect) for c in mesh.colors: c4 = fbx.FbxColor(c.r, c.g, c.b, c.a) colorLayerElement.GetDirectArray().Add(c4) layer.SetVertexColors(colorLayerElement) # diffuse uv layer if (mesh.has_uvs()): uvDiffuseLayerElement = fbx.FbxLayerElementUV.Create( result, 'diffuseUV') uvDiffuseLayerElement.SetMappingMode( fbx.FbxLayerElement.eByControlPoint) uvDiffuseLayerElement.SetReferenceMode(fbx.FbxLayerElement.eDirect) for uv in mesh.uvs: v2 = fbx.FbxVector2(uv.u, uv.v) uvDiffuseLayerElement.GetDirectArray().Add(v2) layer.SetUVs(uvDiffuseLayerElement, fbx.FbxLayerElement.eTextureDiffuse) if (texture): fbxTexture = fbx.FbxFileTexture.Create(pScene, mesh.name + "_Texture") fbxTexture.SetFileName(texture) fbxTexture.SetTextureUse(fbx.FbxTexture.eStandard) fbxTexture.SetMappingType(fbx.FbxTexture.eUV) fbxTexture.SetMaterialUse(fbx.FbxFileTexture.eModelMaterial) fbxTexture.SetSwapUV(False) fbxTexture.SetTranslation(0.0, 0.0) fbxTexture.SetScale(1.0, 1.0) fbxTexture.SetRotation(0.0, 0.0) fbxTexture.Alpha.Set(0.0) pMaterial.Diffuse.ConnectSrcObject(fbxTexture) return result
def import_curve_test_1(): """ 1. Import curve exported from Maya. 2. Move curve node to new scene 3. Manipulate curve data 4. save to new file Seems to work! """ fbx_manager = fbx.FbxManager.Create() io_settings = fbx.FbxIOSettings.Create(fbx_manager, fbx.IOSROOT) fbx_manager.SetIOSettings(io_settings) fbx_importer = fbx.FbxImporter.Create(fbx_manager, "") fbx_importer.Initialize(TEST_IMPORT_FILE, -1, fbx_manager.GetIOSettings()) fbx_scene = fbx.FbxScene.Create(fbx_manager, "TestScene") fbx_importer.Import(fbx_scene) fbx_importer.Destroy() # find curve curve_node = fbx_scene.FindNodeByName("curve1") if not curve_node: raise Exception("Curve node not found") curve_attr = curve_node.GetNodeAttribute() if not isinstance(curve_attr, fbx.FbxNurbsCurve): raise Exception("Curve node is not FbxNurbsCurve") # get curve data if True: knots = curve_attr.GetKnotVector() points = curve_attr.GetControlPoints() print curve_attr.GetControlPointsCount() print knots for point in points: print point return # create new scene new_scene = fbx.FbxScene.Create(fbx_manager, "ExportScene") # clone curve to new scene clone_node = fbx.FbxNode.Create(fbx_manager, "clone_curve") clone_attr = curve_attr.Clone( # Changes to original object propagate to clone. Changes to clone do not propagate to original. # eREFERENCE_CLONE # A deep copy of the object. # Changes to either the original or clone do not propagate to each # other.) fbx.FbxObject.eDeepClone, new_scene) clone_node.SetNodeAttribute(clone_attr) new_scene.GetRootNode().AddChild(clone_node) print "clone: ", clone_attr # check cloned data knots = clone_attr.GetKnotVector() points = clone_attr.GetControlPoints() print knots for point in points: print point # move curve to new scene # remove curve from imported scene fbx_scene.GetRootNode().RemoveChild(curve_node) fbx_scene.DisconnectSrcObject(curve_node) fbx_scene.DisconnectSrcObject(curve_attr) # add to new scene new_scene.GetRootNode().AddChild(curve_node) # manipulate curve curve_attr.SetControlPointAt(fbx.FbxVector4(0.0, 0.0, 50.0, 1.0), 2) # export new scene res = FbxCommon.SaveScene(fbx_manager, new_scene, TEST_EXPORT_FILE_1) print res return True
def create_scene(): fbx_manager = fbx.FbxManager() fbx_scene = fbx.FbxScene.Create(fbx_manager, "prototype_session_scene") root_node = fbx_scene.GetRootNode() # create some nodes loc_1 = fbxUtils.create_locator("loc1", fbx_manager, root_node) loc_2 = fbxUtils.create_locator("loc2", fbx_manager, root_node) loc_3 = fbxUtils.create_locator("loc3", fbx_manager, root_node) # maniuplate locators mat_1 = fbx.FbxAMatrix() mat_1.SetT( fbx.FbxVector4(1, 2, 3, 0) ) mat_1.SetR( fbx.FbxVector4(45, 0, 0, 0) ) # inspect matrix values if False: print mat_1.GetRow(0) print mat_1.GetRow(1) print mat_1.GetRow(2) print mat_1.GetRow(3) # test scale if False: mat_1.SetS( fbx.FbxVector4(2, 2, 2, 0) ) print mat_1.GetRow(0) print mat_1.GetRow(1) print mat_1.GetRow(2) print mat_1.GetRow(3) # set node values loc_1.LclTranslation.Set( fbx.FbxDouble4(*list(mat_1.GetT())) ) loc_1.LclRotation.Set( fbx.FbxDouble4(*list(mat_1.GetR())) ) # test "aim" if False: # the aim matrix method aint gonna work # cos we can only set rows using FbxMatrix # but we can't get Euler values from it # and we can't turn it into FbxAMatrix # so I guess we have to do it the hard way? mat_2 = fbx.FbxMatrix() mat_2.SetRow(0, fbx.FbxVector4(1, 0, 0, 0)) mat_2.SetRow(1, fbx.FbxVector4(0, 1, 0, 0)) mat_2.SetRow(2, fbx.FbxVector4(0, 0, 1, 0)) mat_2.SetRow(3, fbx.FbxVector4(2, 0, 0, 1)) mat_2a = mat_2 * fbx.FbxAMatrix() loc_2.LclTranslation.Set( fbx.FbxDouble4(*list(mat_2a.GetT())) ) loc_2.LclRotation.Set( fbx.FbxDouble4(*list(mat_2a.GetR())) ) # in theory this method should support rotation orders...? # euler aim (x - aim, y - up) x_aim_vector = fbx.FbxVector4(0.5, 0.1, 0.4, 0) y_up_vector = fbx.FbxVector4(-0.2, 1, 0.1, 0) # calculate vectors x_aim_vector.Normalize() y_up_vector.Normalize() z_norm_vector = x_aim_vector.CrossProduct(y_up_vector) # z_norm_vector = y_up_vector.CrossProduct(x_aim_vector) z_norm_vector.Normalize() # y_corrected_up_vector = x_aim_vector.CrossProduct(z_norm_vector) y_corrected_up_vector = z_norm_vector.CrossProduct(x_aim_vector) if False: # debugging print "aim ", x_aim_vector, x_aim_vector.Length() print "up ", y_up_vector, y_up_vector.Length() print "cor up ", y_corrected_up_vector, y_corrected_up_vector.Length() print "norm ", z_norm_vector, z_norm_vector.Length() print "np x", numpy.cross( [0, 1, 0], [0, 0, 1], ) print "np y", numpy.cross( [0, 0, 1], [1, 0, 0], ) print "np z", numpy.cross( [1, 0, 0], [0, 1, 0], ) if False: # create scipy rotation object # using direction cosine matrix directions = [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0] ] x_aim_cosines = [ fbx.FbxVector4(*direction).DotProduct( x_aim_vector, ) for direction in directions ] y_up_cosines = [ fbx.FbxVector4(*direction).DotProduct( y_up_vector, ) for direction in directions ] z_norm_cosines = [ fbx.FbxVector4(*direction).DotProduct( z_norm_vector, ) for direction in directions ] print numpy.array([ x_aim_cosines, y_up_cosines, z_norm_cosines ]) print numpy.rad2deg([ x_aim_cosines, y_up_cosines, z_norm_cosines ]) sp_rot = scipy_rotation.from_dcm( # # [0.0, 0.0, -17.46279830041399] # numpy.rad2deg([ # x_aim_cosines, # y_up_cosines, # z_norm_cosines # ]) # # #[0.0, 0.0, -13.101645932991731] numpy.array([ list(x_aim_vector)[:3], list(y_up_vector)[:3], list(z_norm_vector)[:3] ]).transpose() # [0.0, 0.0, -13.101645932991731] # numpy.array([ # x_aim_cosines, # y_up_cosines, # z_norm_cosines # ]) ) poop_aim = sp_rot.as_euler('ZYX', degrees=True).tolist() euler_aim = sp_rot.as_euler('XYZ', degrees=True).tolist() # test loc_2.LclTranslation.Set( fbx.FbxDouble4(2, 0, 0, 0) ) loc_2.LclRotation.Set( fbx.FbxDouble4(*euler_aim + [0]) ) # test rotation order loc_3.SetRotationOrder( loc_3.eSourcePivot, fbx.eEulerZYX ) loc_3.LclTranslation.Set( fbx.FbxDouble4(3, 0, 0, 0) ) loc_3.LclRotation.Set( fbx.FbxDouble4( *poop_aim + [0] #*sp_rot.as_euler('zyx', degrees=True).tolist() + [0] ) ) loc_1_mat = loc_1.EvaluateGlobalTransform() print loc_1_mat.GetR() loc_2_mat = loc_2.EvaluateGlobalTransform() print loc_2_mat.GetR() loc_3_mat = loc_3.EvaluateGlobalTransform() print loc_3_mat.GetR() return fbx_manager, fbx_scene
def create_skel_nodes(fbx_manager): """Create a root and some joints. """ # create root root_name = "root" root_attr = fbx.FbxSkeleton.Create(fbx_manager, root_name) root_attr.SetSkeletonType(fbx.FbxSkeleton.eRoot) root_node = fbx.FbxNode.Create(fbx_manager, root_name) root_node.SetNodeAttribute(root_attr) # create joint1 joint1_name = "joint1" joint1_attr = fbx.FbxSkeleton.Create(fbx_manager, joint1_name) joint1_attr.SetSkeletonType(fbx.FbxSkeleton.eLimbNode) joint1_node = fbx.FbxNode.Create(fbx_manager, joint1_name) joint1_node.SetNodeAttribute(joint1_attr) joint1_node.LclTranslation.Set(fbx.FbxDouble3(50.0, 0.0, 0.0)) # set prefered angle (both methods work) if True: prop = joint1_node.FindProperty("PreferedAngleX") print prop.IsValid() print prop.Set(15.0) else: joint1_node.SetPreferedAngle( # vector4 will accept 3 args fbx.FbxVector4(0.0, 0.0, 35.0)) # *** set joint orientation **** # not sure what this does?! # joint1_node.SetPivotState( # joint1_node.eSourcePivot, # joint1_node.ePivotActive # ) # # joint1_node.SetPivotState( # joint1_node.eDestinationPivot, # joint1_node.ePivotActive # ) # When this flag is set to false, the RotationOrder, # the Pre/Post rotation values and the rotation limits should be ignored. # (False by default) joint1_node.SetRotationActive(True) # suggestion from forum to update pivots (not supported in Python) # https://forums.autodesk.com/t5/fbx-forum/manipulating-the-prerotation-property/m-p/4278262 # joint1_node.UpdatePivotsAndLimitsFromProperties() if True: # (this method works) # Pivot context identifier. # eSourcePivot: The source pivot context. # eDestinationPivot:The destination pivot context. joint1_node.SetPreRotation( # joint1_node.eDestinationPivot, # != joint orientation joint1_node.eSourcePivot, # == joint orientation fbx.FbxVector4(0.0, 0.0, 15.0)) else: # (this method does not work) # TODO find out why # set joint orientation ???? jo_prop = joint1_node.FindProperty("PreRotation") # jo_cast_prop = fbx.FbxPropertyDouble3(jo_prop) # print help(jo_cast_prop) # jo_cast_prop[2].Set(15.0) print jo_prop.Set(fbx.FbxDouble3(0.0, 0.0, 15.0)) # create joint2 joint2_name = "joint2" joint2_attr = fbx.FbxSkeleton.Create(fbx_manager, joint2_name) joint2_attr.SetSkeletonType(fbx.FbxSkeleton.eLimbNode) joint2_node = fbx.FbxNode.Create(fbx_manager, joint2_name) joint2_node.SetNodeAttribute(joint2_attr) joint2_node.LclTranslation.Set(fbx.FbxDouble3(25.0, 0.0, 0.0)) joint2_node.LclRotation.Set(fbx.FbxDouble3(0.0, 0.0, 45.0)) # add some custom data test_prop = fbx.FbxProperty.Create(joint2_node, fbx.FbxStringDT, "testStringProperty") test_prop.ModifyFlag(fbx.FbxPropertyFlags.eUserDefined, True) print test_prop.Set(fbx.FbxString("some stuff about things")) # dict test # TODO test deserializing this test_prop = fbx.FbxProperty.Create(joint2_node, fbx.FbxStringDT, "testDictProperty") test_prop.ModifyFlag(fbx.FbxPropertyFlags.eUserDefined, True) # animatable double print test_prop.Set( fbx.FbxString( json.dumps({ "test": 1.0, "things": "blah", "stuff": True }))) test_dbl_prop = fbx.FbxProperty.Create(joint2_node, fbx.FbxDoubleDT, "testDoubleProperty") test_dbl_prop.ModifyFlag(fbx.FbxPropertyFlags.eUserDefined, True) test_dbl_prop.ModifyFlag(fbx.FbxPropertyFlags.eAnimatable, True) print test_dbl_prop.Set(16.0) # note: float property gets converted into double # after importing into Maya and exporting out again test_float_prop = fbx.FbxProperty.Create(joint2_node, fbx.FbxFloatDT, "testFloatProperty") test_float_prop.ModifyFlag(fbx.FbxPropertyFlags.eUserDefined, True) # cast_test_prop = print test_float_prop.Set(18.0) test_dbl3_prop = fbx.FbxProperty.Create(joint2_node, fbx.FbxDouble3DT, "testDouble3Property") test_dbl3_prop.ModifyFlag(fbx.FbxPropertyFlags.eUserDefined, True) test_dbl3_prop.ModifyFlag(fbx.FbxPropertyFlags.eAnimatable, True) print test_dbl3_prop.Set( 1.3 # [1.1, 2.2, 3.3] # fbx.FbxDouble3(1.1, 2.2, 3.3) ) # create joint3 joint3_name = "joint3" joint3_attr = fbx.FbxSkeleton.Create(fbx_manager, joint3_name) joint3_attr.SetSkeletonType(fbx.FbxSkeleton.eLimbNode) # if we wanted to use IK: # joint3_attr.SetSkeletonType(fbx.FbxSkeleton.eEffector) joint3_node = fbx.FbxNode.Create(fbx_manager, joint3_name) joint3_node.SetNodeAttribute(joint3_attr) joint3_node.LclTranslation.Set(fbx.FbxDouble3(20.0, 0.0, 0.0)) # Build skeleton node hierarchy root_node.AddChild(joint1_node) joint1_node.AddChild(joint2_node) joint2_node.AddChild(joint3_node) return root_node
def add_entity_to_scene(scene, entity, brush_index): """ Adds a brush as a scene node :param scene: The scene to add the brushes to :param entity: The entity to take the brushes from :param brush_index: The brush index, this should be a unique ID per brush :return The number of brushes added """ # Obtain a reference to the scene's root node. root_node = scene.GetRootNode() for brush in entity.brushes: # ignore requested brushes with certain textures applied #if brush.faces[0].texture is not None and 'Vienna/DKwall03_5_v' in brush.faces[0].texture.texture_path: # continue # Create a new node in the scene. new_node = fbx.FbxNode.Create(scene, 'brushNode{0}'.format(brush_index)) root_node.AddChild(new_node) # Create a new mesh node attribute in the scene, and set it as the new node's attribute new_mesh = fbx.FbxMesh.Create(scene, 'brushMesh{0}'.format(brush_index)) new_node.SetNodeAttribute(new_mesh) # accumulate all of the brush face points brush_points = [] for face in brush.faces: if face.winding is None: # Not all faces work out, this is just some quake quirk or something continue for i in range(0, face.winding.numpoints): point = face.winding.points[i] brush_points.append( fbx.FbxVector4(point[0], point[1], point[2])) # init the control points we are going to set new_mesh.InitControlPoints(len(brush_points)) # set all control points for i in range(0, len(brush_points)): new_mesh.SetControlPointAt(brush_points[i], i) # now join all the points cur_poly = 0 cur_point = 0 for face in brush.faces: if face.winding is None: # Not all faces work out, this is just some quake quirk or something continue new_mesh.BeginPolygon(cur_poly) for i in range(0, face.winding.numpoints): new_mesh.AddPolygon(cur_point) cur_point += 1 new_mesh.EndPolygon() cur_poly += 1 if cur_point != len(brush_points): raise Exception( 'Number of points plotted on polygons not the number of actual polys!' ) brush_index += 1 return len(entity.brushes)