web打包更新

This commit is contained in:
Rowland 2026-03-25 10:45:15 +08:00
parent ab6d543dc0
commit bab5a9bb27
13 changed files with 9896 additions and 17 deletions

View File

@ -31,19 +31,19 @@ DockId=0x0000000D,0
[Window][场景树]
Pos=0,20
Size=339,1008
Size=339,996
Collapsed=0
DockId=0x00000007,0
[Window][属性面板]
Pos=1506,20
Size=346,1008
Pos=1502,20
Size=346,996
Collapsed=0
DockId=0x00000002,0
[Window][控制台]
Pos=341,629
Size=1163,399
Pos=341,617
Size=1159,399
Collapsed=0
DockId=0x00000006,1
@ -59,7 +59,7 @@ Collapsed=0
[Window][WindowOverViewport_11111111]
Pos=0,20
Size=1852,1008
Size=1848,996
Collapsed=0
[Window][测试窗口1]
@ -78,17 +78,17 @@ Size=93,65
Collapsed=0
[Window][新建项目]
Pos=824,402
Pos=724,358
Size=400,300
Collapsed=0
[Window][选择路径]
Pos=626,264
Pos=624,258
Size=600,500
Collapsed=0
[Window][打开项目]
Pos=676,314
Pos=674,308
Size=500,400
Collapsed=0
@ -98,8 +98,8 @@ Size=600,500
Collapsed=0
[Window][资源管理器]
Pos=341,629
Size=1163,399
Pos=341,617
Size=1159,399
Collapsed=0
DockId=0x00000006,0
@ -226,13 +226,13 @@ Size=460,260
Collapsed=0
[Docking][Data]
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1852,1008 Split=X
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1848,996 Split=X
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=2212,1012 Split=X
DockNode ID=0x00000007 Parent=0x00000001 SizeRef=339,1084 Selected=0xE0015051
DockNode ID=0x00000008 Parent=0x00000001 SizeRef=1871,1084 Split=Y
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=2048,683 Split=Y
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=2048,595 Split=Y
DockNode ID=0x0000000D Parent=0x00000005 SizeRef=1318,383 HiddenTabBar=1 Selected=0x43A39006
DockNode ID=0x0000000E Parent=0x00000005 SizeRef=1318,363 CentralNode=1 Selected=0xE0015051
DockNode ID=0x00000006 Parent=0x00000008 SizeRef=2048,399 Selected=0x3A2E05C3
DockNode ID=0x00000006 Parent=0x00000008 SizeRef=2048,399 Selected=0x5428E753
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=346,1012 Selected=0x5DB6FF37

View File

@ -32,6 +32,7 @@ from project.scene_description import (
normalize_scene_description,
save_json,
)
from project.webgl_packager import WebGLPackager
class ProjectManager:
@ -41,6 +42,7 @@ class ProjectManager:
self.project_config = None
self.current_scene_guid = None
self._asset_database = None
self.last_webgl_export_report = None
print("✓ 项目管理系统初始化完成")
@ -2091,6 +2093,55 @@ class ProjectManager:
)
return manifest
def buildWebGLPackage(self, output_dir):
"""将当前项目导出为 WebGL 静态站点目录。"""
try:
if not self.current_project_path:
print("错误: 请先创建或打开一个项目!")
return False
if not output_dir:
print("错误: 请指定 WebGL 打包输出目录!")
return False
project_path = normalize_path(self.current_project_path)
ensure_project_directories(ProjectLayout(project_path))
if hasattr(self.world, "selection") and self.world.selection:
self.world.selection.clearSelection()
print("已取消场景中的物体选中状态")
if not self.saveProject():
print("错误: WebGL 打包前保存场景失败!")
return False
output_dir = normalize_path(output_dir)
packager = WebGLPackager(self.world)
report = packager.package(project_path, output_dir)
self.last_webgl_export_report = report
status = str(report.get("status", "failed") or "failed")
report_path = os.path.join(
str(report.get("output_dir", "") or ""),
"reports",
"export_report.json",
)
if status in ("success", "partial"):
print(f"WebGL打包完成: {status}")
print(f"输出目录: {report.get('output_dir', '')}")
print(f"报告路径: {report_path}")
return True
print("WebGL打包失败")
if report_path:
print(f"报告路径: {report_path}")
return False
except Exception as exc:
print(f"WebGL打包过程出错: {exc}")
return False
def buildPackage(self, build_dir):
"""将当前项目打包为最终运行程序。"""
try:
@ -2707,4 +2758,3 @@ class ProjectManager:
"""更新窗口标题(保留方法以兼容旧代码)"""
# 这个方法现在不需要做任何事情因为我们不再处理UI
pass

2405
project/webgl_packager.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>EG WebGL Scene</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div id="app">
<canvas id="scene-canvas"></canvas>
<div id="status" class="status">Loading scene...</div>
</div>
<script type="module" src="./js/viewer.js"></script>
</body>
</html>

61
templates/webgl/style.css Normal file
View File

@ -0,0 +1,61 @@
:root {
--bg: #0f1115;
--panel: rgba(16, 20, 28, 0.88);
--text: #d6dde9;
--ok: #77d0b9;
--warn: #e2b272;
--err: #f27878;
}
* {
box-sizing: border-box;
}
html,
body,
#app {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background: radial-gradient(circle at 20% 20%, #1b2230 0%, var(--bg) 50%, #090b10 100%);
color: var(--text);
font-family: "Segoe UI", "SF Pro Text", "PingFang SC", sans-serif;
}
#scene-canvas {
width: 100%;
height: 100%;
display: block;
}
.status {
position: fixed;
left: 16px;
bottom: 16px;
max-width: min(640px, calc(100vw - 32px));
padding: 10px 12px;
background: var(--panel);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 8px;
backdrop-filter: blur(4px);
line-height: 1.45;
white-space: pre-wrap;
font-size: 13px;
}
.status.ok {
border-color: rgba(119, 208, 185, 0.5);
color: var(--ok);
}
.status.warn {
border-color: rgba(226, 178, 114, 0.55);
color: var(--warn);
}
.status.error {
border-color: rgba(242, 120, 120, 0.65);
color: var(--err);
}

3923
templates/webgl/vendor/GLTFLoader.js vendored Normal file

File diff suppressed because it is too large Load Diff

1229
templates/webgl/vendor/OrbitControls.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2085
templates/webgl/viewer.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -309,6 +309,95 @@ class AppActions:
self.add_info_message("打开打包项目对话框")
self.show_build_project_dialog = True
def _on_build_webgl_package(self):
"""处理“打包为 WebGL”菜单项。"""
project_manager = getattr(self, "project_manager", None)
if not project_manager:
self.add_error_message("项目管理器未初始化")
return
current_project_path = getattr(project_manager, "current_project_path", None)
if not current_project_path:
self.add_warning_message("请先创建或打开项目再进行WebGL打包")
return
if not self._save_project_impl():
self.add_error_message("打包前自动保存失败已取消WebGL打包")
return
initial_dir = os.path.dirname(current_project_path) if current_project_path else os.getcwd()
selected_dir = self._select_directory_system_dialog("选择 WebGL 打包输出目录", initial_dir)
if not selected_dir:
dialog_error = getattr(self, "_last_directory_dialog_error", "")
if dialog_error:
self.add_warning_message(f"系统目录选择器不可用: {dialog_error}")
self.path_browser_mode = "webgl_build"
self.path_browser_current_path = initial_dir if os.path.isdir(initial_dir) else os.getcwd()
self.path_browser_selected_path = self.path_browser_current_path
self.show_path_browser = True
self._pending_webgl_package = True
self._refresh_path_browser()
self.add_info_message("已切换到内置路径浏览器,请选择输出目录并点击确定")
else:
self.add_info_message("已取消WebGL打包")
return
self._execute_webgl_package(selected_dir)
def _execute_webgl_package(self, selected_dir):
"""执行 WebGL 打包并反馈结果。"""
ok = self.project_manager.buildWebGLPackage(selected_dir)
report = getattr(self.project_manager, "last_webgl_export_report", None) or {}
status = str(report.get("status", "failed") or "failed")
out_dir = str(report.get("output_dir", "") or "")
report_path = os.path.join(out_dir, "reports", "export_report.json") if out_dir else ""
if ok:
missing_count = len(report.get("missing_assets", []) or [])
unsupported_count = len(report.get("unsupported_assets", []) or [])
if status == "partial":
self.add_warning_message(
f"WebGL打包部分成功: 缺失资源 {missing_count},不支持资源 {unsupported_count}"
)
else:
self.add_success_message("WebGL打包成功")
if out_dir:
self.add_info_message(f"输出目录: {out_dir}")
if report_path:
self.add_info_message(f"报告: {report_path}")
return True
self.add_error_message("WebGL打包失败")
if report_path:
self.add_warning_message(f"请检查报告: {report_path}")
return False
def _select_directory_system_dialog(self, title, initial_dir=""):
"""打开系统目录选择器并返回目录路径。"""
self._last_directory_dialog_error = ""
try:
import tkinter as tk
from tkinter import filedialog
if not initial_dir or not os.path.isdir(initial_dir):
initial_dir = os.getcwd()
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
selected_dir = filedialog.askdirectory(
title=title,
initialdir=initial_dir,
mustexist=False,
parent=root,
)
root.destroy()
return os.path.normpath(selected_dir) if selected_dir else ""
except Exception as exc:
self._last_directory_dialog_error = str(exc)
return ""
def _build_project_impl(self, output_path):
"""执行项目打包。"""
if not hasattr(self, "project_manager") or not self.project_manager:

View File

@ -627,6 +627,13 @@ class DialogPanels:
elif self.path_browser_mode == "build_project":
self.build_output_path = self.path_browser_current_path
self.add_info_message(f"已选择打包位置: {self.build_output_path}")
elif self.path_browser_mode == "webgl_build":
output_dir = self.path_browser_current_path
self.add_info_message(f"已选择WebGL输出目录: {output_dir}")
if getattr(self, "_pending_webgl_package", False):
self._pending_webgl_package = False
if hasattr(self, "_execute_webgl_package"):
self._execute_webgl_package(output_dir)
elif self.path_browser_mode == "import_model":
# 导入模型模式:使用选择的文件路径
self.import_file_path = self.path_browser_selected_path

View File

@ -189,6 +189,8 @@ class EditorPanelsTopMixin:
self.app._on_save_as_project()
if imgui.menu_item("打包项目", "", False, True)[1]:
self.app._on_build_project()
if imgui.menu_item("打包为 WebGL", "", False, True)[1]:
self.app._on_build_webgl_package()
imgui.separator()
if imgui.menu_item("退出", "Alt+F4", False, True)[1]:
self.app._on_exit()
@ -544,4 +546,3 @@ class EditorPanelsTopMixin:
)
imgui.pop_style_var(2)

View File

@ -540,6 +540,12 @@ class PanelDelegates:
def _on_build_project(self, *args, **kwargs):
return self.app_actions._on_build_project(*args, **kwargs)
def _on_build_webgl_package(self, *args, **kwargs):
return self.app_actions._on_build_webgl_package(*args, **kwargs)
def _execute_webgl_package(self, *args, **kwargs):
return self.app_actions._execute_webgl_package(*args, **kwargs)
def _build_project_impl(self, *args, **kwargs):
return self.app_actions._build_project_impl(*args, **kwargs)
@ -954,4 +960,3 @@ class PanelDelegates:
def loadScript(self, script_path):
return self.runtime_actions.loadScript(script_path)