Skip to content

logic parts zh

laurel Lin edited this page Aug 22, 2026 · 3 revisions

src/logic/parts.ts — 零件解析与归一化

把 .bbmodel 的 elements / 当前项目选中的元素统一解析成 PartModel,并归一化:底面 y 平移到 0, 模型的对称点平移到 (0,0)。纯函数,可在 Node 中单测(传入 JSON 结构的 elements)。

对称点依据模型格式:Java Block/Item(java_block / java_item)→ (8,8)(画布 0..16, 原点在角上);其他格式(generic/free)→ (0,0)(原点即画布中心)。这样 Java 模式下零件可以在 0..16 画布内做大,而不必受「关于零点对称」的尺寸限制。

原始元素结构

// element 旋转:.bbmodel 数组形式 [rx,ry,rz] 或旧式对象形式
export type ElementRotation =
	| [number, number, number]
	| { angle?: number; axis?: 'x' | 'y' | 'z'; origin?: [number, number, number] };

// 体块元素(type='cube' 或缺省)
export interface RawCubeElement {
	name?: string;
	type?: 'cube';
	from: [number, number, number];
	to: [number, number, number];
	rotation?: ElementRotation;
	origin?: [number, number, number]; // 数组形式旋转时,origin 是 rotation 的同级字段
	faces?: Partial<Record<CubeFaceDirection, { uv?: [number, number, number, number]; rotation?: number; texture?: string | number }>>;
}

// mesh 元素(type='mesh'):顶点表 + 面表;面的 texture 是纹理数组下标(同 cube)
export interface RawMeshElement {
	name?: string;
	type: 'mesh';
	vertices?: Record<string, [number, number, number]>;
	faces?: Record<string, { vertices?: string[]; uv?: number[] | Record<string, any>; rotation?: number; texture?: string | number }>;
	origin?: [number, number, number];
	rotation?: [number, number, number];
}

export type RawElement = RawCubeElement | RawMeshElement;

// .bbmodel 的 textures 数组元素
export interface RawTexture {
	name?: string;
	id?: string | number;   // 纹理 id(面里用 texture 字段引用它)
	source?: string;        // base64 data URL 或桌面文件路径
	uv_width?: number;
	uv_height?: number;
}

// .bbmodel 文件的顶层 JSON 结构
export interface RawBbModel {
	meta?: { model_format?: string; texture_size?: [number, number] };
	resolution?: { width?: number; height?: number }; // Blockbench 5 的模型分辨率(纹理尺寸)
	elements?: RawElement[];
	textures?: RawTexture[];
}

辅助函数

export function isMeshElement(el: RawElement): el is RawMeshElement;
export function symmetryPointForFormat(format: string | undefined): Vec3;      // (8,8) / (0,0)
export function outputOffsetForFormat(format: string | undefined): Vec3;        // 上者的逆(生成时平移)
export function examplePartBox(kind: 'rail' | 'tie', format?: string): { from: Vec3; to: Vec3 }; // 示例钢轨/枕木

元素 → CubeSpec / MeshSpec

// 单个 element → CubeSpec,支持数组 + 对象两种旋转形式
export function elementToCubeSpec(el: RawElement): CubeSpec;

// 只保留 cube 元素 → CubeSpec[](mesh 跳过)
export function elementsToCubeSpecs(elements: RawElement[]): CubeSpec[];

// 提取 mesh 组 → MeshSpec[];面的 texture 引用统一为字符串 key;mesh 的 origin/rotation 烘焙进顶点并
// 置空(否则后续 translate 会对非零 origin 的 mesh 双重位移)
export function extractMeshes(elements: RawElement[]): MeshSpec[];

包围盒

export function computeBBox(cubes: CubeSpec[]): { min: Vec3; max: Vec3 };
export function computeMeshBBox(meshes: MeshSpec[]): { min: Vec3; max: Vec3 };
export function partBBox(cubes: CubeSpec[], meshes: MeshSpec[] = []): { min: Vec3; max: Vec3 };

归一化

normalize 把底面 y 平移到 0、对称点平移到 (0,0);mesh 顶点与 origin 用同一偏移平移,保证 cube 与 mesh 相对位置不变。返回新的 CubeSpec(不污染入参)。

export function normalize(cubes: CubeSpec[], symmetry?: Vec3, meshes: MeshSpec[] = []): PartModel;

纹理

.bbmodel 里 element 的面用 texture 字段引用的是纹理数组的下标(Blockbench 加载器 Texture.all[face.texture]),不是纹理 id,因此源纹理 key 设为 String(index),与面引用对齐。 分辨率优先级:resolution → meta.texture_size → 全部纹理共享的 uv 尺寸 → undefined。

export function parseBbTextures(
	json: RawBbModel
): { textureSize?: [number, number]; textures: SourceTexture[] };

// 三个零件纹理分辨率必须一致;一致则返回该尺寸,否则返回 null(应拒绝生成)
export function consistentTextureSize(parts: { textureSize?: [number, number] }[]): [number, number] | null;

// 给零件源纹理 key 加前缀(L/0、R/0、T/0),使三份零件在「源 key → 导入 Texture」映射里不互相覆盖
// (每份的下标都从 0 开始)。cube 面与 mesh 面一并改写。返回同一 PartModel(就地改写)。
export function scopeTextureKeys(part: PartModel, prefix: string): PartModel;

模型格式与解析入口

// 任一零件含 mesh → 'free'(唯一能容纳 mesh 组的格式);全 cube → Java 方块/物品模型
export function targetFormatForParts(parts: { hasMesh?: boolean }[], currentFormat?: string): string;

export function parseBbModel(json: RawBbModel, format?: string, perTextureUv?: boolean): PartModel;
export function extractFromElements(elements: RawElement[], format?: string): PartModel;

← 返回中文接口文档

Clone this wiki locally