feat: 3D 编辑器支持 - 网格、相机、Gizmo

This commit is contained in:
yhh
2025-12-22 12:40:43 +08:00
parent a1e1189f9d
commit 66d9f428b3
18 changed files with 3646 additions and 50 deletions

View File

@@ -652,6 +652,24 @@ export class EngineBridge implements ITextureEngineBridge, ITextureService, IDyn
this.getEngine().setTransformMode(mode);
}
/**
* Render a 3D gizmo at the specified world position.
* 在指定的世界位置渲染 3D Gizmo。
*
* Only works in 3D render mode. The gizmo will be rendered
* with the current transform mode (move/rotate/scale).
* 仅在 3D 渲染模式下有效。Gizmo 将使用当前的变换模式渲染。
*
* @param x - World X position | 世界 X 坐标
* @param y - World Y position | 世界 Y 坐标
* @param z - World Z position | 世界 Z 坐标
* @param scale - Gizmo scale multiplier | Gizmo 缩放倍数
*/
render3DGizmo(x: number, y: number, z: number, scale: number = 1.0): void {
if (!this.initialized) return;
this.getEngine().render3DGizmo(x, y, z, scale);
}
/**
* Set gizmo visibility.
* 设置辅助工具可见性。
@@ -1334,6 +1352,195 @@ export class EngineBridge implements ITextureEngineBridge, ITextureService, IDyn
}
}
// ===== 3D Rendering API =====
// ===== 3D 渲染 API =====
/**
* Render mode enumeration.
* 渲染模式枚举。
*/
static readonly RenderMode = {
Mode2D: 0,
Mode3D: 1,
} as const;
/**
* Get current render mode.
* 获取当前渲染模式。
*
* @returns 0 for 2D mode, 1 for 3D mode | 0 表示 2D 模式1 表示 3D 模式
*/
getRenderMode(): number {
if (!this.initialized) return 0;
return this.getEngine().getRenderMode();
}
/**
* Set render mode.
* 设置渲染模式。
*
* When switching to 3D mode for the first time, the 3D renderer
* will be lazily initialized.
* 首次切换到 3D 模式时3D 渲染器将被延迟初始化。
*
* @param mode - 0 for 2D, 1 for 3D | 0 表示 2D1 表示 3D
*/
setRenderMode(mode: number): void {
if (!this.initialized) return;
this.getEngine().setRenderMode(mode);
}
/**
* Check if 3D renderer is initialized.
* 检查 3D 渲染器是否已初始化。
*/
has3DRenderer(): boolean {
if (!this.initialized) return false;
return this.getEngine().has3DRenderer();
}
/**
* Get 3D camera position.
* 获取 3D 相机位置。
*
* @returns { x, y, z } or null if 3D renderer is not initialized
* { x, y, z } 或 3D 渲染器未初始化则返回 null
*/
getCamera3DPosition(): { x: number; y: number; z: number } | null {
if (!this.initialized) return null;
const result = this.getEngine().getCamera3DPosition();
if (!result) return null;
return { x: result[0], y: result[1], z: result[2] };
}
/**
* Set 3D camera position.
* 设置 3D 相机位置。
*
* @param x - X coordinate | X 坐标
* @param y - Y coordinate | Y 坐标
* @param z - Z coordinate | Z 坐标
*/
setCamera3DPosition(x: number, y: number, z: number): void {
if (!this.initialized) return;
this.getEngine().setCamera3DPosition(x, y, z);
}
/**
* Get 3D camera rotation as Euler angles (in degrees).
* 获取 3D 相机旋转的欧拉角(角度制)。
*
* @returns { pitch, yaw, roll } in degrees or null
* 角度制的 { pitch, yaw, roll } 或 null
*/
getCamera3DRotation(): { pitch: number; yaw: number; roll: number } | null {
if (!this.initialized) return null;
const result = this.getEngine().getCamera3DRotation();
if (!result) return null;
return { pitch: result[0], yaw: result[1], roll: result[2] };
}
/**
* Set 3D camera rotation from Euler angles (in degrees).
* 使用欧拉角设置 3D 相机旋转(角度制)。
*
* @param pitch - Pitch angle in degrees | 俯仰角(度)
* @param yaw - Yaw angle in degrees | 偏航角(度)
* @param roll - Roll angle in degrees | 滚转角(度)
*/
setCamera3DRotation(pitch: number, yaw: number, roll: number): void {
if (!this.initialized) return;
this.getEngine().setCamera3DRotation(pitch, yaw, roll);
}
/**
* Get 3D camera field of view (in degrees).
* 获取 3D 相机视野角(角度制)。
*
* @returns FOV in degrees or null if 3D renderer not initialized
* 角度制的 FOV 或 null
*/
getCamera3DFov(): number | null {
if (!this.initialized) return null;
const result = this.getEngine().getCamera3DFov();
return result ?? null;
}
/**
* Set 3D camera field of view (in degrees).
* 设置 3D 相机视野角(角度制)。
*
* @param fov - Field of view in degrees (typical: 45-90)
* 视野角(度,通常 45-90
*/
setCamera3DFov(fov: number): void {
if (!this.initialized) return;
this.getEngine().setCamera3DFov(fov);
}
/**
* Set 3D camera projection type.
* 设置 3D 相机投影类型。
*
* @param type - 0 for perspective, 1 for orthographic
* 0 表示透视投影1 表示正交投影
* @param orthoSize - Half-height of orthographic view (only used when type = 1)
* 正交视图的半高度(仅在 type = 1 时使用)
*/
setCamera3DProjection(type: number, orthoSize: number = 5.0): void {
if (!this.initialized) return;
this.getEngine().setCamera3DProjection(type, orthoSize);
}
/**
* Make 3D camera look at a target position.
* 使 3D 相机朝向目标位置。
*
* @param targetX - Target X coordinate | 目标 X 坐标
* @param targetY - Target Y coordinate | 目标 Y 坐标
* @param targetZ - Target Z coordinate | 目标 Z 坐标
*/
camera3DLookAt(targetX: number, targetY: number, targetZ: number): void {
if (!this.initialized) return;
this.getEngine().camera3DLookAt(targetX, targetY, targetZ);
}
/**
* Set 3D camera near and far clip planes.
* 设置 3D 相机近远裁剪面。
*
* @param near - Near clip plane distance | 近裁剪面距离
* @param far - Far clip plane distance | 远裁剪面距离
*/
setCamera3DClipPlanes(near: number, far: number): void {
if (!this.initialized) return;
this.getEngine().setCamera3DClipPlanes(near, far);
}
/**
* Resize 3D viewport.
* 调整 3D 视口大小。
*
* @param width - New width | 新宽度
* @param height - New height | 新高度
*/
resize3D(width: number, height: number): void {
if (!this.initialized) return;
this.getEngine().resize3D(width, height);
}
/**
* Render using 3D mode.
* 使用 3D 模式渲染。
*
* This renders all submitted 3D meshes with the current 3D camera.
* 使用当前 3D 相机渲染所有已提交的 3D 网格。
*/
render3D(): void {
if (!this.initialized) return;
this.getEngine().render3D();
}
/**
* Dispose the bridge and release resources.
* 销毁桥接并释放资源。

View File

@@ -88,8 +88,8 @@ export interface EngineStats {
}
/**
* Camera configuration.
* 相机配置。
* Camera configuration (2D).
* 相机配置2D
*/
export interface CameraConfig {
/** Camera X position. | 相机X位置。 */
@@ -101,3 +101,51 @@ export interface CameraConfig {
/** Rotation in radians. | 旋转角度(弧度)。 */
rotation: number;
}
/**
* 3D Camera position.
* 3D 相机位置。
*/
export interface Camera3DPosition {
/** X coordinate. | X 坐标。 */
x: number;
/** Y coordinate. | Y 坐标。 */
y: number;
/** Z coordinate. | Z 坐标。 */
z: number;
}
/**
* 3D Camera rotation (Euler angles in degrees).
* 3D 相机旋转(欧拉角,角度制)。
*/
export interface Camera3DRotation {
/** Pitch angle in degrees. | 俯仰角(度)。 */
pitch: number;
/** Yaw angle in degrees. | 偏航角(度)。 */
yaw: number;
/** Roll angle in degrees. | 滚转角(度)。 */
roll: number;
}
/**
* Projection type for 3D camera.
* 3D 相机的投影类型。
*/
export enum ProjectionType {
/** Perspective projection. | 透视投影。 */
Perspective = 0,
/** Orthographic projection. | 正交投影。 */
Orthographic = 1,
}
/**
* Render mode.
* 渲染模式。
*/
export enum RenderMode {
/** 2D rendering mode. | 2D 渲染模式。 */
Mode2D = 0,
/** 3D rendering mode. | 3D 渲染模式。 */
Mode3D = 1,
}

View File

@@ -5,6 +5,22 @@
* 初始化panic hook以在控制台显示更好的错误信息。
*/
export function init(): void;
/**
* Render mode enumeration.
* 渲染模式枚举。
*/
export enum RenderMode {
/**
* 2D rendering mode (orthographic camera, no depth test).
* 2D渲染模式正交相机无深度测试
*/
Mode2D = 0,
/**
* 3D rendering mode (perspective/orthographic camera, depth test enabled).
* 3D渲染模式透视/正交相机,启用深度测试)。
*/
Mode3D = 1,
}
/**
* Game engine main interface exposed to JavaScript.
* 暴露给JavaScript的游戏引擎主接口。
@@ -143,11 +159,37 @@ export class GameEngine {
* The material ID for referencing this material | 用于引用此材质的ID
*/
createMaterial(name: string, shader_id: number, blend_mode: number): number;
/**
* Get current render mode.
* 获取当前渲染模式。
*
* Returns 0 for 2D mode, 1 for 3D mode.
* 返回 0 表示 2D 模式1 表示 3D 模式。
*/
getRenderMode(): number;
/**
* Check if 3D renderer is initialized.
* 检查 3D 渲染器是否已初始化。
*/
has3DRenderer(): boolean;
/**
* Remove a material.
* 移除材质。
*/
removeMaterial(material_id: number): boolean;
/**
* Render a 3D gizmo at the specified world position.
* 在指定的世界位置渲染 3D Gizmo。
*
* Only works in 3D render mode. The gizmo will be rendered
* with the current transform mode (move/rotate/scale).
* 仅在 3D 渲染模式下有效。Gizmo 将使用当前的变换模式渲染。
*
* # Arguments | 参数
* * `x`, `y`, `z` - World position | 世界位置
* * `scale` - Gizmo scale multiplier | Gizmo 缩放倍数
*/
render3DGizmo(x: number, y: number, z: number, scale: number): void;
/**
* Resize a specific viewport.
* 调整特定视口大小。
@@ -182,6 +224,18 @@ export class GameEngine {
* 当为 false运行时模式编辑器专用 UI如网格、gizmos、坐标轴指示器会自动隐藏。
*/
setEditorMode(is_editor: boolean): void;
/**
* Set render mode.
* 设置渲染模式。
*
* # Arguments | 参数
* * `mode` - 0 for 2D, 1 for 3D | 0 表示 2D1 表示 3D
*
* When switching to 3D mode for the first time, the 3D renderer
* will be lazily initialized.
* 首次切换到 3D 模式时3D 渲染器将被延迟初始化。
*/
setRenderMode(mode: number): void;
/**
* Set gizmo visibility.
* 设置辅助工具可见性。
@@ -241,6 +295,16 @@ export class GameEngine {
* 添加胶囊Gizmo边框。
*/
addGizmoCapsule(x: number, y: number, radius: number, half_height: number, rotation: number, r: number, g: number, b: number, a: number): void;
/**
* Make 3D camera look at a target position.
* 使 3D 相机朝向目标位置。
*/
camera3DLookAt(target_x: number, target_y: number, target_z: number): void;
/**
* Get 3D camera field of view (in degrees).
* 获取 3D 相机视野角(角度制)。
*/
getCamera3DFov(): number | undefined;
/**
* 获取纹理加载状态
* Get texture loading state
@@ -262,6 +326,14 @@ export class GameEngine {
* * `canvas_id` - HTML canvas element ID | HTML canvas元素ID
*/
registerViewport(id: string, canvas_id: string): void;
/**
* Set 3D camera field of view (in degrees).
* 设置 3D 相机视野角(角度制)。
*
* Only affects perspective projection mode.
* 仅影响透视投影模式。
*/
setCamera3DFov(fov_degrees: number): void;
/**
* Set a material's vec2 uniform.
* 设置材质的vec2 uniform。
@@ -447,6 +519,22 @@ export class GameEngine {
* 使用特定ID编译着色器。
*/
compileShaderWithId(shader_id: number, vertex_source: string, fragment_source: string): void;
/**
* Get 3D camera position.
* 获取 3D 相机位置。
*
* Returns [x, y, z] or null if 3D renderer is not initialized.
* 返回 [x, y, z],如果 3D 渲染器未初始化则返回 null。
*/
getCamera3DPosition(): Float32Array | undefined;
/**
* Get 3D camera rotation as Euler angles (in degrees).
* 获取 3D 相机旋转的欧拉角(角度制)。
*
* Returns [pitch, yaw, roll] or null if 3D renderer is not initialized.
* 返回 [pitch, yaw, roll],如果 3D 渲染器未初始化则返回 null。
*/
getCamera3DRotation(): Float32Array | undefined;
/**
* Get texture ID by path.
* 按路径获取纹理ID。
@@ -455,6 +543,21 @@ export class GameEngine {
* * `path` - Image path to lookup | 要查找的图片路径
*/
getTextureIdByPath(path: string): number | undefined;
/**
* Set 3D camera position.
* 设置 3D 相机位置。
*/
setCamera3DPosition(x: number, y: number, z: number): void;
/**
* Set 3D camera rotation using Euler angles (in degrees).
* 使用欧拉角设置 3D 相机旋转(角度制)。
*
* # Arguments | 参数
* * `pitch` - Rotation around X axis (degrees) | X 轴旋转(角度)
* * `yaw` - Rotation around Y axis (degrees) | Y 轴旋转(角度)
* * `roll` - Rotation around Z axis (degrees) | Z 轴旋转(角度)
*/
setCamera3DRotation(pitch: number, yaw: number, roll: number): void;
/**
* Create a material with a specific ID.
* 使用特定ID创建材质。
@@ -488,11 +591,25 @@ export class GameEngine {
* * `path` - Image path to lookup | 要查找的图片路径
*/
getTextureSizeByPath(path: string): Float32Array | undefined;
/**
* Set 3D camera projection type.
* 设置 3D 相机投影类型。
*
* # Arguments | 参数
* * `projection_type` - 0 for Perspective, 1 for Orthographic
* * `ortho_size` - Half-height of orthographic view (only used when projection_type = 1)
*/
setCamera3DProjection(projection_type: number, ortho_size: number): void;
/**
* 获取正在加载中的纹理数量
* Get the number of textures currently loading
*/
getTextureLoadingCount(): number;
/**
* Set 3D camera near and far clip planes.
* 设置 3D 相机近裁剪面和远裁剪面。
*/
setCamera3DClipPlanes(near: number, far: number): void;
/**
* Create a new game engine instance.
* 创建新的游戏引擎实例。
@@ -529,6 +646,19 @@ export class GameEngine {
* * `height` - New viewport height | 新视口高度
*/
resize(width: number, height: number): void;
/**
* Render 3D content.
* 渲染 3D 内容。
*
* Should be called after submitting 3D meshes.
* 应在提交 3D 网格后调用。
*/
render3D(): void;
/**
* Resize 3D renderer viewport.
* 调整 3D 渲染器视口大小。
*/
resize3D(width: number, height: number): void;
/**
* Get canvas width.
* 获取画布宽度。
@@ -550,6 +680,7 @@ export interface InitOutput {
readonly gameengine_addGizmoCircle: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
readonly gameengine_addGizmoLine: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
readonly gameengine_addGizmoRect: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => void;
readonly gameengine_camera3DLookAt: (a: number, b: number, c: number, d: number) => void;
readonly gameengine_clear: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_clearAllTextures: (a: number) => void;
readonly gameengine_clearScissorRect: (a: number) => void;
@@ -563,14 +694,19 @@ export interface InitOutput {
readonly gameengine_getBackendName: (a: number) => [number, number];
readonly gameengine_getBackendVersion: (a: number) => [number, number];
readonly gameengine_getCamera: (a: number) => [number, number];
readonly gameengine_getCamera3DFov: (a: number) => number;
readonly gameengine_getCamera3DPosition: (a: number) => [number, number];
readonly gameengine_getCamera3DRotation: (a: number) => [number, number];
readonly gameengine_getMaxTextureSize: (a: number) => number;
readonly gameengine_getOrLoadTextureByPath: (a: number, b: number, c: number) => [number, number, number];
readonly gameengine_getRenderMode: (a: number) => number;
readonly gameengine_getTextureIdByPath: (a: number, b: number, c: number) => number;
readonly gameengine_getTextureLoadingCount: (a: number) => number;
readonly gameengine_getTextureSizeByPath: (a: number, b: number, c: number) => any;
readonly gameengine_getTextureState: (a: number, b: number) => [number, number];
readonly gameengine_getViewportCamera: (a: number, b: number, c: number) => [number, number];
readonly gameengine_getViewportIds: (a: number) => [number, number];
readonly gameengine_has3DRenderer: (a: number) => number;
readonly gameengine_hasMaterial: (a: number, b: number) => number;
readonly gameengine_hasShader: (a: number, b: number) => number;
readonly gameengine_height: (a: number) => number;
@@ -584,13 +720,21 @@ export interface InitOutput {
readonly gameengine_removeMaterial: (a: number, b: number) => number;
readonly gameengine_removeShader: (a: number, b: number) => number;
readonly gameengine_render: (a: number) => [number, number];
readonly gameengine_render3D: (a: number) => [number, number];
readonly gameengine_render3DGizmo: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_renderOverlay: (a: number) => [number, number];
readonly gameengine_renderToViewport: (a: number, b: number, c: number) => [number, number];
readonly gameengine_resize: (a: number, b: number, c: number) => void;
readonly gameengine_resize3D: (a: number, b: number, c: number) => void;
readonly gameengine_resizeViewport: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_screenToWorld: (a: number, b: number, c: number) => [number, number];
readonly gameengine_setActiveViewport: (a: number, b: number, c: number) => number;
readonly gameengine_setCamera: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_setCamera3DClipPlanes: (a: number, b: number, c: number) => void;
readonly gameengine_setCamera3DFov: (a: number, b: number) => void;
readonly gameengine_setCamera3DPosition: (a: number, b: number, c: number, d: number) => void;
readonly gameengine_setCamera3DProjection: (a: number, b: number, c: number) => void;
readonly gameengine_setCamera3DRotation: (a: number, b: number, c: number, d: number) => void;
readonly gameengine_setClearColor: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_setEditorMode: (a: number, b: number) => void;
readonly gameengine_setMaterialBlendMode: (a: number, b: number, c: number) => number;
@@ -599,6 +743,7 @@ export interface InitOutput {
readonly gameengine_setMaterialVec2: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
readonly gameengine_setMaterialVec3: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number;
readonly gameengine_setMaterialVec4: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
readonly gameengine_setRenderMode: (a: number, b: number) => [number, number];
readonly gameengine_setScissorRect: (a: number, b: number, c: number, d: number, e: number) => void;
readonly gameengine_setShowGizmos: (a: number, b: number) => void;
readonly gameengine_setShowGrid: (a: number, b: number) => void;
@@ -614,8 +759,8 @@ export interface InitOutput {
readonly gameengine_width: (a: number) => number;
readonly gameengine_worldToScreen: (a: number, b: number, c: number) => [number, number];
readonly init: () => void;
readonly wasm_bindgen__convert__closures_____invoke__h0cae3d4947da04cb: (a: number, b: number) => void;
readonly wasm_bindgen__closure__destroy__h0c01365f59f73f28: (a: number, b: number) => void;
readonly wasm_bindgen__convert__closures_____invoke__h256074d77f4ce876: (a: number, b: number) => void;
readonly wasm_bindgen__closure__destroy__h14ac3db10f717d1a: (a: number, b: number) => void;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_exn_store: (a: number) => void;