Ship the WeChat hot-update catalogs and the camp, TideWhale T2, UI atlas, and animation-lab work.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
udx
2026-10-24 18:04:41 +08:00
co-authored by Cursor
parent 6ebc9401ce
commit 45e62132c8
1432 changed files with 2971856 additions and 2798 deletions
+81 -11
View File
@@ -7,6 +7,7 @@ import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
SUPPORTED_MODEL_EXTENSIONS = (".fbx", ".glb", ".gltf")
FBX_YUP_EXPORT_VERSION = 2
def model_format(path):
@@ -87,18 +88,87 @@ def prepare_game_export(obj, restore_axis=None):
def export_fbx_source_yup(filepath):
"""导出与混元 GLB 相同的 Y-up FBX。调用前顶点须已是 Y-up。"""
"""Export prepared Y-up geometry as an actual Y-up FBX scene.
prepare_game_export stores Y-up vertices inside Blender's Z-up workspace.
Passing those straight to the FBX exporter adds a -90 X object rotation,
so consumers applying the complete FBX transform see a horizontal model.
Restore Blender Z-up on temporary copies, then bake the export conversion.
Leave source meshes, UVs, transforms and selection unchanged for callers.
"""
import math
import bpy
bpy.ops.export_scene.fbx(
filepath=filepath,
use_selection=True,
object_types={"MESH"},
axis_forward="-Z",
axis_up="Y",
bake_space_transform=False,
path_mode="STRIP",
embed_textures=False,
)
from mathutils import Matrix
selected = list(bpy.context.selected_objects)
active = bpy.context.view_layer.objects.active
meshes = [obj for obj in selected if obj.type == "MESH"]
if not meshes:
raise ValueError("Select at least one prepared Y-up mesh for FBX export")
copies = []
source_names = [(source, source.name) for source in meshes]
try:
bpy.ops.object.select_all(action="DESELECT")
for source, source_name in source_names:
duplicate = source.copy()
duplicate.data = source.data.copy()
copies.append(duplicate)
bpy.context.scene.collection.objects.link(duplicate)
source.name = source_name + "__fbx_export_source"
duplicate.name = source_name
duplicate.parent = None
duplicate.matrix_world = Matrix.Rotation(math.pi / 2, 4, "X") @ source.matrix_world
duplicate.select_set(True)
bpy.context.view_layer.objects.active = copies[0]
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
bpy.ops.export_scene.fbx(
filepath=filepath,
use_selection=True,
object_types={"MESH"},
axis_forward="-Z",
axis_up="Y",
bake_space_transform=True,
apply_unit_scale=True,
apply_scale_options="FBX_SCALE_ALL",
bake_anim=False,
path_mode="STRIP",
embed_textures=False,
)
return validate_fbx_yup_scene(filepath)
finally:
for duplicate in copies:
mesh = duplicate.data
bpy.data.objects.remove(duplicate, do_unlink=True)
if mesh.users == 0:
bpy.data.meshes.remove(mesh)
for obj in selected:
obj.select_set(True)
for source, source_name in source_names:
source.name = source_name
bpy.context.view_layer.objects.active = active
def validate_fbx_yup_scene(filepath):
"""Reject the old extra node rotation even when raw vertices look Y-up."""
from io_scene_fbx import parse_fbx
root, _ = parse_fbx.parse(str(filepath))
def properties(element):
block = next(e for e in element.elems if e.id == b"Properties70")
return {p.props[0].decode(): list(p.props[4:]) for p in block.elems}
settings = properties(next(e for e in root.elems if e.id == b"GlobalSettings"))
if settings.get("UpAxis") != [1] or settings.get("UpAxisSign") != [1]:
raise ValueError("Exported FBX scene is not +Y-up")
objects = next(e for e in root.elems if e.id == b"Objects")
for model in (e for e in objects.elems if e.id == b"Model"):
values = properties(model)
if any(abs(v) > 1e-5 for v in values.get("Lcl Rotation", [0, 0, 0])):
raise ValueError("Exported FBX retains an unbaked node rotation")
if any(abs(v - 1) > 1e-5 for v in values.get("Lcl Scaling", [1, 1, 1])):
raise ValueError("Exported FBX retains an unbaked node scale")
return {"exportVersion": FBX_YUP_EXPORT_VERSION, "sceneUp": "+Y",
"nodeRotationBaked": True, "nodeScaleBaked": True,
"unitScaleFactor": settings.get("UnitScaleFactor", [1])[0]}
TOLERANCE = 0.03 # 面数相对误差容忍
MAX_RETRY = 2 # ratio 修正轮数上限