ModelTranslator: Unity asset templates (texture/material/model meta) with GUID reuse
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user