UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

272 lines (271 loc) 11.1 kB
/** * ModelGeometryUtilities * * Shared utility methods for working with Minecraft Bedrock geometry models. * Contains static methods for: * - Cube bounding box calculations * - Bone transform accumulation * - Point rotation around pivots * - UV coordinate calculations * - Depth sorting for rendering * - Orthographic and isometric 2D projection * * These utilities are used by: * - ModelMeshFactory (3D BabylonJS rendering) * - Model2DRenderer (2D SVG rendering) * - BlockbenchModel (format conversion) * * COORDINATE SYSTEMS: * ------------------- * Minecraft Bedrock Edition: * - Right-handed coordinate system * - +Y is up, +Z is forward (towards the viewer in default orientation), +X is right * - Units are in 1/16ths of a block (so divide by 16 for block units) * * For 2D rendering (front view): * - X maps to screen X (positive = right) * - Y maps to screen Y (positive = up, but SVG Y is inverted) * - Z is depth (positive = towards viewer, used for sorting) * * VIEW DIRECTIONS: * ---------------- * Orthographic (axis-aligned, shows 1 face): * - front, back, left, right, top, bottom * * Isometric (3D-like, shows 3 faces): * - iso-front-right: north + east + up faces (classic Minecraft inventory style) * - iso-front-left: north + west + up faces * - iso-back-right: south + east + up faces * - iso-back-left: south + west + up faces * * Last Updated: December 2025 */ import { IGeometry, IGeometryBone, IGeometryBoneCube } from "./IModelGeometry"; /** * Represents accumulated bone transform including parent transforms */ export interface IBoneTransform { pivot: number[]; rotation: number[]; parentName?: string; } /** * Represents a projected 2D rectangle from a cube face */ export interface IProjectedFace { /** Screen X coordinate of bounding box top-left corner */ x: number; /** Screen Y coordinate of bounding box top-left corner */ y: number; /** Width in screen units (bounding box) */ width: number; /** Height in screen units (bounding box) */ height: number; /** Depth for z-ordering (larger = closer to viewer) - uses maxDepth by default for painter's algorithm */ depth: number; /** Minimum depth (closest vertex to camera) */ minDepth: number; /** Maximum depth (furthest vertex from camera) */ maxDepth: number; /** Average depth across all vertices */ avgDepth: number; /** Original cube reference */ cube: IGeometryBoneCube; /** Bone that contains this cube */ bone: IGeometryBone; /** Face name (north, south, east, west, up, down) */ face: string; /** UV coordinates for texture sampling [u, v, width, height] */ uv: number[]; /** * Projected corner vertices for isometric views. * Order: bottom-left, bottom-right, top-right, top-left (counter-clockwise) * Each point is {x, y}. Present only for isometric projections. */ vertices?: { x: number; y: number; }[]; } /** * Represents a 3D axis-aligned bounding box */ export interface IBoundingBox { minX: number; maxX: number; minY: number; maxY: number; minZ: number; maxZ: number; } /** * View direction for 2D projection. * Standard views: front, back, left, right, top, bottom (orthographic axis-aligned) * Isometric views: iso-front-right, iso-front-left, iso-back-right, iso-back-left * These provide a 3D-like view showing 3 faces at once (classic Minecraft inventory style) */ export type ViewDirection = "front" | "back" | "left" | "right" | "top" | "bottom" | "iso-front-right" | "iso-front-left" | "iso-back-right" | "iso-back-left"; /** * Check if a view direction is isometric (shows 3 faces at once) */ export declare function isIsometricView(direction: ViewDirection): boolean; export default class ModelGeometryUtilities { /** * Calculate the center point of a cube in world coordinates. * Cube origin is the minimum corner, so center = origin + size/2. */ static getCubeCenter(cube: IGeometryBoneCube): number[]; /** * Calculate the 8 corner vertices of a cube in world coordinates. * Returns array of [x, y, z] for each corner. */ static getCubeVertices(cube: IGeometryBoneCube): number[][]; /** * Get the bounding box of a cube (axis-aligned, before rotation). */ static getCubeBoundingBox(cube: IGeometryBoneCube): IBoundingBox; /** * Get the bounding box of an entire geometry model. */ static getGeometryBoundingBox(geometry: IGeometry): IBoundingBox; /** * Check if a rotation array has any non-zero rotation. */ static hasRotation(rotation: number[] | undefined): boolean; /** * Build a map of bone transforms for a geometry. * Includes bind_pose_rotation and parent relationships. */ static buildBoneTransformMap(geometry: IGeometry): Map<string, IBoneTransform>; /** * Rotate a point around a pivot by the given rotation (in degrees). * Applies rotations in Minecraft order: X, then Y, then Z. */ static rotatePointAroundPivot(point: number[], pivot: number[], rotationDegrees: number[]): number[]; /** * Calculate the normal vector of a face from its rotated corner vertices. * Uses cross product of two edges to get the outward-facing normal. * * @param corners Array of 4 corner points [[x,y,z], ...] in counter-clockwise order * @returns Normalized face normal [nx, ny, nz] */ static calculateFaceNormal(corners: number[][]): number[]; /** * Get the camera/view direction vector for a given view direction. * This is the direction FROM the camera TO the scene (opposite of camera facing). * * For orthographic/isometric rendering, we use a parallel projection, so * the view direction is constant (not dependent on position). */ static getViewDirectionVector(viewDirection: ViewDirection): number[]; /** * Check if a face should be visible (not backface-culled) given the view direction. * * @param faceNormal The normal vector of the face after rotations * @param viewDirection The current view direction * @returns true if the face is visible (facing the camera), false if backface-culled */ static isFaceVisible(faceNormal: number[], viewDirection: ViewDirection): boolean; /** * Calculate UV coordinates for a specific face of a cube. * Handles both legacy [u, v] format and per-face UV format. * * @returns [u, v, width, height] in texture pixels */ static getCubeFaceUV(cube: IGeometryBoneCube, face: string, texWidth: number, texHeight: number): { u: number; v: number; width: number; height: number; }; /** * Get the faces that would be visible from a given view direction. * Returns the face names that should be rendered. * * In Minecraft, entities face north (-Z) by default. So: * - "front" view = looking at their face = we see the "north" face * - "back" view = looking at their back = we see the "south" face * * For isometric views, we see 3 faces at once: * - "iso-front-right" = north + east + up (viewing from the front-right above) * - "iso-front-left" = north + west + up (viewing from the front-left above) * - "iso-back-right" = south + east + up (viewing from the back-right above) * - "iso-back-left" = south + west + up (viewing from the back-left above) */ static getVisibleFaces(viewDirection: ViewDirection): string[]; /** * Get the secondary faces that would be partially visible from a given view. * Used for isometric or 3/4 view rendering with depth effects. * For isometric views, all 3 primary faces are already in getVisibleFaces, so no secondary. */ static getSecondaryVisibleFaces(viewDirection: ViewDirection): string[]; /** * Options for perspective projection in projectPoint. */ static perspectiveOptions: { enabled: boolean; strength: number; focalLength: number; /** Reference depth - points at this depth have no perspective distortion */ referenceDepth: number; }; /** * Center offset for isometric rotation. * When set, isometric rotation is applied around this center point instead of the world origin. * This ensures models with large Z offsets (like cow.v2) render correctly in isometric views. * Set to null to disable (rotate around world origin). */ static isometricCenterOffset: number[] | null; /** * Apply isometric rotation to a 3D point. * For classic isometric view: rotate around Y-axis, then ~30° around X-axis. * This produces the familiar Minecraft inventory-style 3D view. * * Rotation angles for each view (entity faces north/-Z by default): * - iso-front-right: -135° (see north + east + up) * - iso-front-left: +135° (see north + west + up) * - iso-back-right: -45° (see south + east + up) * - iso-back-left: +45° (see south + west + up) * * @param point 3D point [x, y, z] * @param yRotation Y-axis rotation in degrees * @param centerOffset Optional 3D offset to subtract before rotation (for centering) * @returns Rotated point [x, y, z] */ static applyIsometricRotation(point: number[], yRotation: number, centerOffset?: number[]): number[]; /** * Project a 3D point to 2D screen coordinates. * When perspectiveOptions.enabled is true, applies perspective projection * so that points farther from the camera converge toward the center. * * @param point 3D point [x, y, z] * @param viewDirection View direction * @param scale Scale multiplier * @returns {x, y, depth} where x/y are screen coordinates and depth is for z-ordering */ static projectPoint(point: number[], viewDirection: ViewDirection, scale?: number): { x: number; y: number; depth: number; }; /** * Get projected 2D rectangle for a cube face. * This is the core projection algorithm for 2D rendering. */ static projectCubeFace(cube: IGeometryBoneCube, bone: IGeometryBone, face: string, viewDirection: ViewDirection, boneTransforms: Map<string, IBoneTransform>, scale?: number): IProjectedFace | null; /** * Get all visible faces from a geometry for a given view direction. * Sorted by depth (back to front) for proper occlusion. */ static getProjectedFaces(geometry: IGeometry, viewDirection: ViewDirection, scale?: number, includeSecondary?: boolean): IProjectedFace[]; /** * Calculate the normalized UV coordinates for a face. * Returns coordinates in range [0, 1]. */ static getNormalizedUV(u: number, v: number, width: number, height: number, texWidth: number, texHeight: number): { uMin: number; vMin: number; uMax: number; vMax: number; }; }