fbx格式转换

目录

fbx转bvh

bvh转fbx

npz转换为fbx

npz转换为fbx代码:

convert2fbx.py


fbx转bvh

https://github.com/SinMDM/SinMDM/blob/0296efba20ae5875b6f1c092d277ea274e8ceda2/utils/fbx2bvh.py

"""
This code is a variation of https://github.com/rubenvillegas/cvpr2018nkn/blob/master/datasets/fbx2bvh.py
"""
from glob import glob
import os
import os.path as ospimport bpyprint('start')
in_dir = '<path to folder containing fbx file>'
out_dir = in_dir + '/fbx2bvh'  # in_dir.replace('fbx', 'bvh')
fbx_files = glob(osp.join(in_dir, '*.fbx'))
for idx, in_file in enumerate(fbx_files):print(in_file)in_file_no_path = osp.split(in_file)[1]motion_name = osp.splitext(in_file_no_path)[0]rel_in_file = osp.relpath(in_file, in_dir)rel_out_file = osp.join(osp.split(rel_in_file)[0], '{}'.format(motion_name), '{}.bvh'.format(motion_name))rel_dir = osp.split(rel_out_file)[0]out_file = osp.join(out_dir, rel_out_file)os.makedirs(osp.join(out_dir, rel_dir), exist_ok=True)bpy.ops.import_scene.fbx(filepath=in_file)action = bpy.data.actions[-1]assert action.frame_range[0] < 9999 and action.frame_range[1] > -9999  # checking because of Kfir's codebpy.ops.export_anim.bvh(filepath=out_file,frame_start=action.frame_range[0],frame_end=action.frame_range[1], root_transform_only=True)bpy.data.actions.remove(bpy.data.actions[-1])print('{} processed. #{} of {}'.format(out_file, idx, len(fbx_files)))

bvh转fbx

npy库:

import os.pathimport bpy
import sysbvh_in = r'D:\project\MHFormer-pose\baitao.bvh'
bvh_in = r'D:\project\MHFormer-pose\9_0122_mh.bvh'
fbx_out = "aa.fbx"filename=os.path.basename(bvh_in)file_name_with_extension = os.path.basename(bvh_in)# 使用 splitext 分割文件名和后缀
filename, file_extension = os.path.splitext(file_name_with_extension)fbx_out = filename+".fbx"
# Import the BVH file
# See https://docs.blender.org/api/current/bpy.ops.import_anim.html?highlight=import_anim#module-bpy.ops.import_animbpy.ops.wm.read_factory_settings(use_empty=True)bpy.ops.import_anim.bvh(filepath=bvh_in, filter_glob="*.bvh", global_scale=0.0001, frame_start=1, target='ARMATURE',use_fps_scale=False, use_cyclic=False, rotate_mode='NATIVE', axis_forward='Z', axis_up='Y')
#
# # Export as FBX
# # See https://docs.blender.org/api/current/bpy.ops.export_scene.html
# bpy.ops.export_scene.fbx(filepath=fbx_out, axis_forward='Z',
#                          axis_up='Y', use_selection=True, apply_scale_options='FBX_SCALE_NONE')# bpy.ops.import_anim.bvh(filepath=bvh_in, update_scene_fps=True, update_scene_duration=True)# Ensure correct scene frame range
assert len(bpy.data.actions) == 1
frame_range = bpy.data.actions[0].frame_range
bpy.context.scene.frame_start = int(frame_range[0])
bpy.context.scene.frame_end = int(frame_range[1])# Add some mesh data so UE allows import
bpy.data.objects[filename].name = "animation"
bpy.ops.mesh.primitive_plane_add()
bpy.data.objects["Plane"].name = filename
bpy.data.objects["animation"].select_set(True)
bpy.ops.object.parent_set()  # Parent the "animation" object to cube# Export
bpy.ops.export_scene.fbx(filepath=fbx_out, check_existing=False)

npz转换为fbx

https://github.com/Arthur151/ROMP/blob/4eebd3647f57d291d26423e51f0d514ff7197cb3/simple_romp/tools/convert2fbx.py

依赖项

mathutils

pip install mathutils

npz转换为fbx代码:

需要两个模板:

male_model_path = './models/SMPL_m_unityDoubleBlends_lbs_10_scale5_207_v1.0.0.fbx'
female_model_path = './models/SMPL_f_unityDoubleBlends_lbs_10_scale5_207_v1.0.0.fbx'

要求npz中有字典results和sequence_results

frame_results = np.load(input_path, allow_pickle=True)['results'][()] sequence_results = np.load(input_path, allow_pickle=True)['sequence_results'][()]

convert2fbx.py

import os
import sys
import time
import argparse
import numpy as np
from math import radianstry:import bpy
except:print('Missing bpy, install via pip, please install bpy by yourself if failed.')os.system('pip install future-fstrings')os.system('pip install tools/bpy-2.82.1 && post_install')import bpy
try:from mathutils import Matrix, Vector, Quaternion, Euler
except:os.system('pip install mathutils==2.81.2')from mathutils import Matrix, Vector, Quaternion, Euler# Globals
# Add your UNIX paths here!
male_model_path = './models/SMPL_m_unityDoubleBlends_lbs_10_scale5_207_v1.0.0.fbx'
female_model_path = './models/SMPL_f_unityDoubleBlends_lbs_10_scale5_207_v1.0.0.fbx'
character_model_path = None'''
python tools/convert2fbx.py --input=/home/yusun/BEV_results/video_results.npz --output=/home/yusun/BEV_results/dance.fbx --gender=female
'''fps_source = 24
fps_target = 24gender = 'male'  # femalesupport_formats = ['.fbx', '.glb', '.bvh']bone_name_from_index = {0: 'Pelvis', 1: 'L_Hip', 2: 'R_Hip', 3: 'Spine1', 4: 'L_Knee', 5: 'R_Knee', 6: 'Spine2', 7: 'L_Ankle', 8: 'R_Ankle', 9: 'Spine3', 10: 'L_Foot', 11: 'R_Foot', 12: 'Neck', 13: 'L_Collar', 14: 'R_Collar', 15: 'Head', 16: 'L_Shoulder', 17: 'R_Shoulder', 18: 'L_Elbow',19: 'R_Elbow', 20: 'L_Wrist', 21: 'R_Wrist', 22: 'L_Hand', 23: 'R_Hand'}# To use other avatar for animation, please define the corresponding 3D skeleton like this.
bone_name_from_index_character = {0: 'Hips', 1: 'RightUpLeg', 2: 'LeftUpLeg', 3: 'Spine', 4: 'RightLeg', 5: 'LeftLeg', 6: 'Spine1', 7: 'RightFoot', 8: 'LeftFoot', 9: 'Spine2', 10: 'LeftToeBase', 11: 'RightToeBase', 12: 'Neck', 13: 'LeftHandIndex1', 14: 'RightHandIndex1', 15: 'Head',16: 'LeftShoulder', 17: 'RightShoulder', 18: 'LeftArm', 19: 'RightArm', 20: 'LeftForeArm', 21: 'RightForeArm', 22: 'LeftHand', 23: 'RightHand'}# Helper functions# Computes rotation matrix through Rodrigues formula as in cv2.Rodrigues
# Source: smpl/plugins/blender/corrective_bpy_sh.py
def Rodrigues(rotvec):theta = np.linalg.norm(rotvec)r = (rotvec / theta).reshape(3, 1) if theta > 0. else rotveccost = np.cos(theta)mat = np.asarray([[0, -r[2], r[1]], [r[2], 0, -r[0]], [-r[1], r[0], 0]])return (cost * np.eye(3) + (1 - cost) * r.dot(r.T) + np.sin(theta) * mat)# Setup scene
def setup_scene(model_path, fps_target):scene = bpy.data.scenes['Scene']############################ Engine independent setup###########################scene.render.fps = fps_target# Remove default cubeif 'Cube' in bpy.data.objects:bpy.data.objects['Cube'].select_set(True)bpy.ops.object.delete()# Import gender specific .fbx template filebpy.ops.import_scene.fbx(filepath=model_path)# Process single pose into keyframed bone orientations
def process_pose(current_frame, pose, trans, pelvis_position):if pose.shape[0] == 72:rod_rots = pose.reshape(24, 3)else:rod_rots = pose.reshape(26, 3)mat_rots = [Rodrigues(rod_rot) for rod_rot in rod_rots]# Set the location of the Pelvis bone to the translation parameterarmature = bpy.data.objects['Armature']bones = armature.pose.bones# Pelvis: X-Right, Y-Up, Z-Forward (Blender -Y)root_location = Vector((100 * trans[1], 100 * trans[2], 100 * trans[0])) - pelvis_position# Set absolute pelvis location relative to Pelvis bone headbones[bone_name_from_index[0]].location = root_location# bones['Root'].location = Vector(trans)bones[bone_name_from_index[0]].keyframe_insert('location', frame=current_frame)for index, mat_rot in enumerate(mat_rots, 0):if index >= 24:continuebone = bones[bone_name_from_index[index]]bone_rotation = Matrix(mat_rot).to_quaternion()quat_x_90_cw = Quaternion((1.0, 0.0, 0.0), radians(-90))# quat_x_n135_cw = Quaternion((1.0, 0.0, 0.0), radians(-135))# quat_x_p45_cw = Quaternion((1.0, 0.0, 0.0), radians(45))# quat_y_90_cw = Quaternion((0.0, 1.0, 0.0), radians(-90))quat_z_90_cw = Quaternion((0.0, 0.0, 1.0), radians(-90))if index == 0:# Rotate pelvis so that avatar stands upright and looks along negative Y avisbone.rotation_quaternion = (quat_x_90_cw @ quat_z_90_cw) @ bone_rotationelse:bone.rotation_quaternion = bone_rotationbone.keyframe_insert('rotation_quaternion', frame=current_frame)return# Process all the poses from the pose file
def process_poses(input_path, gender, fps_source, fps_target, subject_id=-1):print('Processing: ' + input_path)frame_results = np.load(input_path, allow_pickle=True)['results'][()]sequence_results = np.load(input_path, allow_pickle=True)['sequence_results'][()]poses, trans = [], []if len(sequence_results) > 0:subject_ids = list(sequence_results.keys())if subject_id == -1 or subject_id not in subject_ids:print('Get motion sequence with subject IDs:', subject_ids)subject_id = int(input('Please select one subject ID (int):'))poses = np.array(sequence_results[subject_id]['smpl_thetas'])trans = np.array(sequence_results[subject_id]['cam_trans'])else:print('Missing tracking IDs in results. Using the first pose results for animation.')print('To get the tracking IDs, please use temporal optimization during inference.')frame_names = sorted(list(frame_results.keys()))poses, trans = np.zeros((len(frame_names), 72)), np.zeros((len(frame_names), 3))for inds, frame_name in enumerate(frame_names):poses[inds] = frame_results[frame_name]['smpl_thetas'][0]trans[inds] = frame_results[frame_name]['cam_trans'][0]if gender == 'female':model_path = female_model_pathfor k, v in bone_name_from_index.items():bone_name_from_index[k] = 'f_avg_' + velif gender == 'male':model_path = male_model_pathfor k, v in bone_name_from_index.items():bone_name_from_index[k] = 'm_avg_' + velif gender == 'character':model_path = character_model_pathfor k, v in bone_name_from_index_character.items():bone_name_from_index[k] = 'mixamorig1:' + velse:print('ERROR: Unsupported gender: ' + gender)sys.exit(1)# Limit target fps to source fpsif fps_target > fps_source:fps_target = fps_sourceprint('Gender:', gender)print('Number of source poses: ', poses.shape[0])print('Source frames-per-second: ', fps_source)print('Target frames-per-second: ', fps_target)print('--------------------------------------------------')setup_scene(model_path, fps_target)scene = bpy.data.scenes['Scene']sample_rate = int(fps_source / fps_target)scene.frame_end = (int)(poses.shape[0] / sample_rate)# Retrieve pelvis world position.# Unit is [cm] due to Armature scaling.# Need to make copy since reference will change when bone location is modified.armaturee = bpy.data.armatures[0]ob = bpy.data.objects['Armature']armature = ob.databpy.ops.object.mode_set(mode='EDIT')# get specific bone name 'Bone'pelvis_bone = armature.edit_bones[bone_name_from_index[0]]# pelvis_bone = armature.edit_bones['f_avg_Pelvis']pelvis_position = Vector(pelvis_bone.head)bpy.ops.object.mode_set(mode='OBJECT')source_index = 0frame = 1offset = np.array([0.0, 0.0, 0.0])while source_index < poses.shape[0]:print('Adding pose: ' + str(source_index))# Go to new framescene.frame_set(frame)process_pose(frame, poses[source_index], (trans[source_index] - offset), pelvis_position)source_index += sample_rateframe += 1return framedef rotate_armature(use):if use == True:# Switch to Pose Modebpy.ops.object.posemode_toggle()# Find the Armature & Bonesob = bpy.data.objects['Armature']armature = ob.databones = armature.bonesrootbone = bones[0]# Find the Root bonefor bone in bones:if "avg_root" in bone.name:rootbone = bonerootbone.select = True# Rotate the Root bone by 90 euler degrees on the Y axis. Set --rotate_Y=False if the rotation is not needed.bpy.ops.transform.rotate(value=1.5708, orient_axis='Y', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, True, False), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1,use_proportional_connected=False, use_proportional_projected=False, release_confirm=True)# Revert back to Object Modebpy.ops.object.posemode_toggle()def export_animated_mesh(output_path):# Create output directory if neededoutput_dir = os.path.dirname(output_path)if not os.path.isdir(output_dir):os.makedirs(output_dir, exist_ok=True)# Fix Rotationrotate_armature(args.rotate_y)# Select only skinned mesh and rigbpy.ops.object.select_all(action='DESELECT')bpy.data.objects['Armature'].select_set(True)bpy.data.objects['Armature'].children[0].select_set(True)if output_path.endswith('.glb'):print('Exporting to glTF binary (.glb)')# Currently exporting without shape/pose shapes for smaller file sizesbpy.ops.export_scene.gltf(filepath=output_path, export_format='GLB', export_selected=True, export_morph=False)elif output_path.endswith('.fbx'):print('Exporting to FBX binary (.fbx)')bpy.ops.export_scene.fbx(filepath=output_path, use_selection=True, add_leaf_bones=False)elif output_path.endswith('.bvh'):bpy.ops.export_anim.bvh(filepath=output_path, root_transform_only=False)else:print('ERROR: Unsupported export format: ' + output_path)sys.exit(1)returnif __name__ == '__main__':if bpy.app.background:parser = argparse.ArgumentParser(description='Create keyframed animated skinned SMPL mesh from VIBE output')# parser.add_argument('--input', dest='input_path', type=str, default=r'D:\project\MHFormer-pose\output\9\output_3D\output_keypoints_3d.npz',  # '../demo/videos/sample_video2_results.npz',parser.add_argument('--input', dest='input_path', type=str, default=r'D:\project\MHFormer-pose\output\baitao\output_3D\output_keypoints_3d.npz',  # '../demo/videos/sample_video2_results.npz',help='Input file or directory')parser.add_argument('--output', dest='output_path', type=str, default='key_3d.fbx',  # '../demo/videos/sample_video2.fbx',help='Output file or directory')parser.add_argument('--fps_source', type=int, default=fps_source, help='Source framerate')parser.add_argument('--fps_target', type=int, default=fps_target, help='Target framerate')parser.add_argument('--gender', type=str, default=gender, help='Always use specified gender')parser.add_argument('--subject_id', type=int, default=-1, help='Detected person ID to use for fbx animation')parser.add_argument('--rotate_y', type=bool, default=True, help='whether to rotate the root bone on the Y axis by -90 on export. Otherwise it may be rotated incorrectly')args = parser.parse_args()input_path = args.input_pathoutput_path = args.output_pathprint('Input path: ' + input_path)print('Output path: ' + output_path)if not os.path.exists(input_path):print('ERROR: Invalid input path')sys.exit(1)fps_source = args.fps_sourcefps_target = args.fps_targetgender = args.genderstartTime = time.perf_counter()cwd = os.getcwd()# Turn relative input/output paths into absolute pathsif not input_path.startswith(os.path.sep):input_path = os.path.join(cwd, input_path)if not output_path.startswith(os.path.sep):output_path = os.path.join(cwd, output_path)if os.path.splitext(output_path)[1] not in support_formats:print('ERROR: Invalid output format, we only support', support_formats)sys.exit(1)# Process pose fileposes_processed = process_poses(input_path=input_path, gender=gender, fps_source=fps_source, fps_target=fps_target, subject_id=args.subject_id)export_animated_mesh(output_path)print('--------------------------------------------------')print('Animation export finished, save to ', output_path)print('Poses processed: ', poses_processed)print('Processing time : ', time.perf_counter() - startTime)print('--------------------------------------------------')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/640962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker运行redis,jdk,nginx

Redis 1.查询redis [rootlocalhost ~]# docker search redis NAME DESCRIPTION STARS OFFICIAL redis Redis is an open source key-value store that… 12620 …

Vue关于router-link的使用和部分代码

//使用router-link和a标签差不多&#xff0c;重点是在vue-router中需要在对应的js文件中createRouter里面配置path的路径和createWebHistory&#xff08;createWebhashHistory&#xff09;的导入 //main.js中需要use(router),就可以进行路径的使用&#xff0c;下面是简单的写法…

白话编程--数据篇(1)基本数据类型

前言 数据是程序的另一个重要组成部分.对于程序的两个理解,一是在实现逻辑;二是在处理数据.综合起来,程序以处理数据的方式表达逻辑. 引入 什么是数据?数据的概念是相当广泛的.他相当于客观世界中的"物体".用一个桔子来做类比,我们可以把桔皮,桔梗,桔的汁液,桔的籽…

快速找到文件夹中匹配和不匹配的图片文件

一、脚本简介 在日常的软件开发和数据处理中&#xff0c;经常需要处理大量的文件和数据。针对一些分类的模型结果&#xff0c;这个脚本可以帮助快速找到文件夹中匹配和不匹配的图片文件。 二、完整代码 import osdef find_mismatched_images(folder1, folder2, subfolder):#…

04 双向链表

目录 1.双向链表 2.实现 3.OJ题 4.链表和顺序表对比 1. 双向链表 前面写了单向链表&#xff0c;复习一下 无头单向非循环链表&#xff1a;结构简单&#xff0c;一般不会单独用来存数据。实际中更多作为其他数据结构的子结构&#xff0c;如哈希桶、图的邻接等。另外这种结构在…

windows用mingw(g++)编译opencv,opencv_contrib,并install安装

windows下用mingw编译opencv貌似不支持cuda&#xff0c;选cuda会报错&#xff0c;我无法解决&#xff0c;所以没选cuda&#xff0c;下面两种编译方式支持。 如要用msvc编译opencv&#xff0c;参考我另外一篇文章 https://blog.csdn.net/weixin_44733606/article/details/1357…

初识人工智能,一文读懂机器学习之逻辑回归知识文集(1)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

进击的 Serverless:Java 应用如何从容地面对突增流量

作者&#xff1a;袭周、十眠 让我们从一个十分常见的业务场景说起。 移动互联网时代&#xff0c;许许多多的业务都有着流量的周期性变化&#xff0c;无论是直播、游戏、点单系统、电商平台等等&#xff0c;都会存在着流量的高峰与波谷。如果采用固定的计算资源部署服务&#…

02-docker下部署seata

官方部署文档 http://seata.io/zh-cn/docs/ops/deploy-by-docker 配置参数说明 http://seata.io/zh-cn/docs/user/configurations 1、镜像拉取 docker pull seata-server2、复制配置文件 mkdir /home/server/seata cd /home/server/seata docker run -d -p 8091:8091 -p 709…

sqli-labs通关笔记(less-11 ~ less16)

上一篇文章说了sqli-labs的less-1到less-10的注入方法&#xff0c;这一篇从less-11开始。 由于从11关开始都是post请求&#xff0c;不会像前十关一样存在符号转成url编码的麻烦&#xff0c;所以不再使用apifox&#xff0c;直接从页面上进行测试。 Less-11 老规矩&#xff0c;…

解决vue 2.6通过花生壳ddsn(内网穿透)实时开发报错Invalid Host header和websocket

请先核对自己的vue版本&#xff0c;我的是2.6.14&#xff0c;其他版本未测试 起因 这两天在维护一个基于高德显示多个目标&#xff08;门店&#xff09;位置的项目&#xff0c;由于高德要求定位必须使用https服务&#xff0c;遂在本地无法获取到定位坐标信息&#xff0c;于是…

JVM实战篇:GC调优

目录 一.GC调优的核心指标 1.1吞吐量&#xff08;Throughput&#xff09; 1.2延迟&#xff08;Latency&#xff09; 1.3内存使用量 二.GC调优的方法 2.1监控工具 Jstat工具 VisualVm插件 Prometheus Grafana 2.2诊断原因 GC日志 GC Viewer GCeasy 2.3常见的GC模…

Unity中Interface修饰符:初学者指南

什么是Interface&#xff1f; 在Unity和其他面向对象的编程语境中&#xff0c;interface是一种特殊的结构&#xff0c;它定义了一组方法和属性&#xff0c;但不提供它们的实现。在C#中&#xff0c;interface是通过关键字interface来声明的。它像是一个合约&#xff0c;规定了实…

手把手教你开发第一个HarmonyOS (鸿蒙)移动应用

⼀、移动应⽤开发的介绍 移动应⽤开发: AndroidIOSHarmonyOS &#xff08;鸿蒙&#xff09; ⼆、HarmonyOS介绍 文档概览-HarmonyOS应用开发官网 2.1 系统的定义 2.1.1 系统的定位 HarmonyOS有三⼤特征&#xff1a; 搭载该操作系统的设备在系统层⾯融为⼀体、形成超级终…

opencv#27模板匹配

图像模板匹配原理 例如给定一张图片&#xff0c;如上图大矩阵所示&#xff0c;然后给定一张模板图像&#xff0c;如上图小矩阵。 我们在大图像中去搜索与小图像中相同的部分或者是最为相似的内容。比如我们在图像中以灰色区域给出一个与模板图像尺寸大小一致的区域&#xff0c;…

编译onnxruntime+OpenVINO,提示“Unsupported OpenVINO version“(已解决)

编译OnnxRuntimeOpenVINO&#xff0c;提示"Unsupported OpenVINO version"(已解决) 昨天刚填完编译OnnxRuntimeOneDNN的坑&#xff0c;今天编译了一天的OnnxRuntimeOpenVINO&#xff0c;一直接提示Unsupported OpenVINO version&#xff0c;无法编译通过。 CMake E…

展开说说provide和inject

写在前面 今天讲一下关于vue组件传值里面的其中一个跨组件传值&#xff0c;之前文章写过一篇关于组件传值&#xff0c;里面也有提过关于这块跨组件传值的方式&#xff0c;其中就提到了provide 和 inject的方式&#xff0c;但是并没有展开说&#xff0c;今天就简单的展开说一下&…

CRM的定义、功能,以及国内外CRM系统排名

什么是客户关系管理? CRM是(客户关系管理)的缩写&#xff0c;是一个管理与客户关系的系统。CRM的主要功能是管理基本客户信息和购买历史的客户管理、分析潜在客户和新客户的客户分析、对询问的自动回复的响应以及通过电子邮件通讯和研讨会吸引客户。它是加强和维护与客户和潜…

opencv#30 线性滤波

均值滤波原理 均值滤波步骤 Step1:求和。 Step2:计算平均值。 所谓均值滤波&#xff0c;就是求平均值的意思。我们假设在一个3*3的范围内有一个图像&#xff0c;其中这个图像每一个像素可能含有噪声&#xff0c;也可能不含噪声&#xff0c;我们是不知道的&#xff0c;因此通…

持续集成工具Jenkins的使用之配置篇(二)

上一篇 &#xff1a;持续集成工具Jenkins的安装配置之安装篇(一)-CSDN博客 接上文 三.Jenkins配置 Jenkins配置主要是针对创建构建任务前做的一些基本配置&#xff0c;这些配置有些是必须的&#xff0c;有些是可以帮我们提高效率的&#xff0c;总之都是Jenkins管理员都要会的…