317 lines
8.0 KiB
Python
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)
|