Files
AIC-Project/Tools/ModelTranslator/unity_assets.py
T

317 lines
8.0 KiB
Python

"""Unity 资产(.meta / .mat)文本模板与 GUID 管理。纯 stdlib,可独立测试。"""
import os
import re
import uuid
XPBR_SHADER_GUID = "cab897163f45445fa34263d6670bfc9e" # Client/Assets/Game/shader/XShader/XPbr.shader.meta
_GUID_RE = re.compile(r"^guid: ([0-9a-f]{32})", re.M)
def new_guid():
return uuid.uuid4().hex
def guid_for(asset_path):
"""资产已有 .meta 则复用其中 guid(重复转换不破坏 Unity 引用),否则新分配。"""
meta = asset_path + ".meta"
if os.path.isfile(meta):
with open(meta, "r", encoding="utf-8") as f:
m = _GUID_RE.search(f.read())
if m:
return m.group(1)
return new_guid()
def safe_name(name):
return re.sub(r"[^0-9A-Za-z_\-]", "_", name).strip("_") or "mat"
def texture_meta(guid, srgb, max_size):
return """fileFormatVersion: 2
guid: {guid}
TextureImporter:
internalIDToNameTable: []
externalObjects: {{}}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: {srgb}
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: {max_size}
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {{x: 0.5, y: 0.5}}
spritePixelsToUnits: 100
spriteBorder: {{x: 0, y: 0, z: 0, w: 0}}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: {max_size}
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {{}}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
""".format(guid=guid, srgb=1 if srgb else 0, max_size=max_size)
def material_yaml(name, shader_guid, base_tex_guid, mix_tex_guid, alpha_test):
keywords = "\n - _ALPHATEST_ON" if alpha_test else " []"
return """%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {{fileID: 0}}
m_PrefabInstance: {{fileID: 0}}
m_PrefabAsset: {{fileID: 0}}
m_Name: {name}
m_Shader: {{fileID: 4800000, guid: {shader_guid}, type: 3}}
m_Parent: {{fileID: 0}}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:{keywords}
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {{}}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _MainTex:
m_Texture: {{fileID: 2800000, guid: {base_tex_guid}, type: 3}}
m_Scale: {{x: 1, y: 1}}
m_Offset: {{x: 0, y: 0}}
- _MixTex:
m_Texture: {{fileID: 2800000, guid: {mix_tex_guid}, type: 3}}
m_Scale: {{x: 1, y: 1}}
m_Offset: {{x: 0, y: 0}}
m_Ints: []
m_Floats:
- _AO: 1
- _AlphaTest: {alpha_test}
- _Cutoff: 0.5
- _Metallic: 1
- _Roughness: 1
m_Colors:
- _BaseColor: {{r: 1, g: 1, b: 1, a: 1}}
m_BuildTextureStacks: []
""".format(name=name, shader_guid=shader_guid, base_tex_guid=base_tex_guid,
mix_tex_guid=mix_tex_guid, keywords=keywords,
alpha_test=1 if alpha_test else 0)
def material_meta(guid):
return """fileFormatVersion: 2
guid: {guid}
NativeFormatImporter:
externalObjects: {{}}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
""".format(guid=guid)
def model_meta(guid, material_remaps):
"""material_remaps: [(fbx 内材质名, mat 文件 guid), ...]"""
if material_remaps:
ext = "externalObjects:\n"
for mat_name, mat_guid in material_remaps:
ext += (" - first:\n"
" type: UnityEngine:Material\n"
" assembly: UnityEngine.CoreModule\n"
" name: {n}\n"
" second: {{fileID: 2100000, guid: {g}, type: 2}}\n"
).format(n=mat_name, g=mat_guid)
else:
ext = "externalObjects: {}\n"
return """fileFormatVersion: 2
guid: {guid}
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
{ext} materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {{instanceID: 0}}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
""".format(guid=guid, ext=ext)