323 lines
8.4 KiB
Python
323 lines
8.4 KiB
Python
"""Unity 资产(.meta / .mat)文本模板与 GUID 管理。纯 stdlib,可独立测试。
|
||
|
||
模板采自 Unity 2022.3(TextureImporter serializedVersion 12 / Material 8 /
|
||
ModelImporter 22200);升级 Unity 后如导入异常,在编辑器导出同类资产 diff 更新模板。"""
|
||
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):
|
||
try:
|
||
with open(meta, "r", encoding="utf-8", errors="replace") as f:
|
||
m = _GUID_RE.search(f.read())
|
||
except OSError:
|
||
m = None # meta 损坏/不可读时按无 meta 处理,重新分配
|
||
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)
|