Compare commits

...

69 Commits
ch ... main

Author SHA1 Message Date
Hector
b3d758a3e3 拖动导入模型帧率异常修复,添加web视图 2026-02-26 18:04:12 +08:00
Hector
79b9aa44dc 拖动导入模型帧率异常修复,添加web视图 2026-02-26 17:57:00 +08:00
Hector
fe373c0e5d 碰撞体可以正常选择不同形状添加 2026-02-26 15:21:18 +08:00
Hector
19235ca43a Merge remote-tracking branch 'refs/remotes/origin/geng' into IMgui_hu 2026-02-26 14:24:09 +08:00
Hector
405e8a9ad3 灯光移动问题修复,模型动画可以正常播放 2026-02-26 11:52:42 +08:00
ayuan9957
eeb5dd193b refactor: extract model drag-and-drop service 2026-02-26 11:31:40 +08:00
ayuan9957
0fa75b7937 模型拖拽 2026-02-26 11:03:44 +08:00
Hector
69d83c6ab5 编辑操作,地形生成,材质系统问题修复 2026-02-25 17:16:24 +08:00
Hector
2766fb9faa Merge remote-tracking branch 'origin/IMgui_hu' into IMgui_hu
# Conflicts:
#	imgui.ini
2026-02-25 15:07:33 +08:00
Hector
f26b14cb40 模型父子级关系修复 2026-02-25 15:06:54 +08:00
ayuan9957
35a75bba29 renderpipiline 更新 2026-02-25 14:56:09 +08:00
Hector
a00b276233 IMGui 2026-02-25 14:42:22 +08:00
Hector
b7abab4f93 IMGui 2026-02-25 14:27:43 +08:00
Hector
26b8e0d93f Merge remote-tracking branch 'origin/imgui' into imgui
# Conflicts:
#	main.py
2026-02-25 11:53:48 +08:00
Hector
ae0df4ca3b IMGui 2026-02-25 11:53:06 +08:00
Hector
62fe0628d8 IMGui 2026-02-25 11:49:31 +08:00
73e6e64a2e vr修改 2026-02-06 14:39:22 +08:00
3b1b547ed8 修复项目加载 2026-01-28 11:31:04 +08:00
8b6b8daf9b 移除qt依赖 2026-01-28 10:17:05 +08:00
33e62bd1e4 移除qt依赖 2026-01-28 10:06:36 +08:00
f07a394d9f ui替换 2026-01-27 15:58:41 +08:00
a167767890 ui替换 2026-01-27 10:04:02 +08:00
ced0eedc7a ui替换 2026-01-27 10:00:39 +08:00
887737f139 ui替换 2026-01-27 09:53:12 +08:00
2124de7de5 ui替换 2026-01-26 16:31:10 +08:00
cbbbf065ac ui替换 2026-01-26 15:25:33 +08:00
058cfe454d ui替换 2026-01-26 11:03:29 +08:00
e42d3cfa30 ui替换 2026-01-26 10:43:48 +08:00
403c4d34f8 ui替换 2026-01-26 10:39:27 +08:00
385103e252 ui替换 2026-01-23 17:38:13 +08:00
99d4979af8 ui替换 2026-01-23 16:39:51 +08:00
fbf71fd6a2 ui替换 2026-01-23 16:05:54 +08:00
bde899a04f ui替换 2026-01-23 15:05:57 +08:00
35d28f4e2b ui替换 2026-01-23 14:16:58 +08:00
30a5669bc5 ui替换 2026-01-22 11:13:01 +08:00
99ef5c0253 ui替换 2026-01-22 10:46:53 +08:00
ef9fabd43d ui替换 2026-01-21 17:18:14 +08:00
d7a5f420c4 ui替换 2026-01-21 16:12:33 +08:00
ae6395b88e ui替换 2026-01-21 14:14:23 +08:00
52b07aa64f ui替换 2026-01-21 10:04:26 +08:00
497ecc8608 ui替换 2026-01-21 09:59:13 +08:00
0860182b11 ui替换 2026-01-20 09:19:55 +08:00
35cecd6008 ui替换 2026-01-19 09:46:16 +08:00
9424ddd0c2 ui替换 2026-01-16 09:36:35 +08:00
6a7b6b6959 ui替换 2026-01-08 17:43:43 +08:00
3f6ae9185e ui替换 2026-01-08 16:32:44 +08:00
1ad2086525 ui替换 2026-01-08 16:30:59 +08:00
1fc3e154d1 ui替换 2026-01-08 14:25:40 +08:00
Hector
69e2bda47e 版本号 2025-12-15 09:10:19 +08:00
e2e432d52d 编译修复 2025-12-12 16:16:15 +08:00
d7d7cc0cbb 动画修复 2025-12-12 15:19:38 +08:00
ddb4fd9527 动画修复 2025-12-12 15:18:59 +08:00
5e255e7c88 动画修复 2025-12-12 15:15:06 +08:00
7a3fbfeb91 动画修复 2025-12-12 14:53:40 +08:00
Hector
79e21d572d windows的run.bat,修复动画路径 2025-12-12 14:23:59 +08:00
0a1abebe24 添加脚本 2025-12-12 10:29:45 +08:00
1a92f12dfd Merge pull request 'HJD' (#11) from HJD into main
Reviewed-on: #11
2025-12-04 07:31:42 +00:00
Hector
2776c587c1 修复windows无法播放视频 2025-12-04 15:27:01 +08:00
Hector
ee63a10c19 最新 2025-12-04 01:49:07 +08:00
Hector
32a6cb65e1 Merge remote-tracking branch 'refs/remotes/origin/addRender' into HJD 2025-12-04 01:47:14 +08:00
Hector
7570ce8242 修复添加pyqtwebengine后windows系统会无法正常显示画面问题 2025-11-21 11:59:52 +08:00
0623908db0 解决中文字体无法加载问题 2025-11-11 14:43:43 +08:00
Hector
d75d21f0f3 支持不同环境下对同一场景中模型的动画控制 2025-11-06 11:08:42 +08:00
Hector
7270031f25 Merge remote-tracking branch 'origin/addRender' into HJD 2025-11-06 10:31:11 +08:00
Hector
176995652b 修复windows无法播放动画问题 2025-11-06 10:30:39 +08:00
5882ac4716 可见性状态方法移除 2025-11-06 09:23:02 +08:00
3d5356a594 增加控制灯光的显示隐藏,并支持模型,GUI,灯光的显示隐藏保存场景后重新加载保存时的状态。 2025-11-04 17:02:31 +08:00
a3711c57ea 光照编辑,图形编辑窗口 2025-11-04 11:12:11 +08:00
6cf616d1bb 添加插件系统 2025-10-30 15:01:29 +08:00
909 changed files with 57803 additions and 265808 deletions

117
.gitignore vendored
View File

@ -1,57 +1,60 @@
__pycache__/
*.pyc
.idea/
【模板】模型及算法与功能对应清单.docx
【模板】GY知识-产品模块架构及功能清单和主要应用场景说明.docx
1.json
2.json
3.json
4.json
6.json
功能清单.md
模型及算法与功能对应清单(完整版).md
维修系统使用说明.md
audio_demo_config.json
create_test_audio.py
demo_universal_dialog.py
Dock按钮样式统一说明.md
Dock面板标题样式线完成说明.md
exam_result_20250926_004454.json
exam_result_20250926_010628.json
exam_result_20250926_011746.json
exam_result_20250926_090330.json
exam_result_20250926_111756.json
exam_test_config.json
Figma布局优化说明.md
Figma设计分析与菜单栏优化文档.md
Figma样式优化完成说明.md
manual_tools_config.json
pm.txt
simple_menubar_test.py
test_audio.py
test_basic_audio.py
test_exam_tool_error.py
test_full_audio_playback.py
test_menu_visibility.py
test_mode_selection.py
test_mp3_audio.py
test_pygame_audio.py
test_score_config.py
test_simple_audio.py
tool_test_config.json
UI设计文档.md
UniversalMessageDialog使用说明.md
.codex/settings/kiroCodex-settings.json
data/projects.json
RenderPipelineFile/config/daytime.yaml
Resources/audio/README.md
Resources/model/a.glb
Resources/model/b.glb
Resources/model/c.glb
Resources/model/JQB_auto_converted.glb
Resources/model/Untitled.glb
Resources/models/Women_1.glb
Subjects/test_maintenance_config.json
Resources/models/Women_1.glb
Resources/models/Women_1.glb
Resources/models/Women_1.glb
__pycache__/
*.pyc
.idea/
【模板】模型及算法与功能对应清单.docx
【模板】GY知识-产品模块架构及功能清单和主要应用场景说明.docx
1.json
2.json
3.json
4.json
6.json
功能清单.md
模型及算法与功能对应清单(完整版).md
维修系统使用说明.md
audio_demo_config.json
create_test_audio.py
demo_universal_dialog.py
Dock按钮样式统一说明.md
Dock面板标题样式线完成说明.md
exam_result_20250926_004454.json
exam_result_20250926_010628.json
exam_result_20250926_011746.json
exam_result_20250926_090330.json
exam_result_20250926_111756.json
exam_test_config.json
Figma布局优化说明.md
Figma设计分析与菜单栏优化文档.md
Figma样式优化完成说明.md
manual_tools_config.json
pm.txt
simple_menubar_test.py
test_audio.py
test_basic_audio.py
test_exam_tool_error.py
test_full_audio_playback.py
test_menu_visibility.py
test_mode_selection.py
test_mp3_audio.py
test_pygame_audio.py
test_score_config.py
test_simple_audio.py
tool_test_config.json
UI设计文档.md
UniversalMessageDialog使用说明.md
.codex/settings/kiroCodex-settings.json
data/projects.json
RenderPipelineFile/config/daytime.yaml
Resources/audio/README.md
Resources/model/a.glb
Resources/model/b.glb
Resources/model/c.glb
Resources/model/JQB_auto_converted.glb
Resources/model/Untitled.glb
Resources/models/Women_1.glb
Subjects/test_maintenance_config.json
Resources/models/Women_1.glb
Resources/models/Women_1.glb
Resources/models/Women_1.glb
/venv/
/engine/
/panda3d_imgui-1.1.0-py3-none-any.whl

28
.idea/EG.iml generated
View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (eg)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (eg)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

12
.idea/misc.xml generated
View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (PythonProject)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (EG)" project-jdk-type="Python SDK" />
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (PythonProject)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
</project>

View File

@ -1,4 +1,4 @@
{
"python-envs.pythonProjects": [],
"kiroAgent.configureMCP": "Disabled"
{
"python-envs.pythonProjects": [],
"kiroAgent.configureMCP": "Disabled"
}

219
AGENTS.md Normal file
View File

@ -0,0 +1,219 @@
# EG 项目概览与开发指南
## 项目简介
EG 是一个基于 Panda3D 引擎开发的 3D 编辑器和游戏引擎集成了高级渲染管线、VR 支持、物理模拟、脚本系统等功能。该项目主要用于创建 3D 场景、游戏开发和交互式应用程序。
## 核心技术栈
- **渲染引擎**: Panda3D 1.10.15 + RenderPipeline (延迟渲染、PBR材质)
- **GUI框架**: PyQt5 + imgui_bundle (用于编辑器界面)
- **VR支持**: OpenVR 2.2.0
- **脚本系统**: Python 3.10.12
- **其他依赖**: PyQt5-WebEngine, assimp, pillow 等
## 项目架构
### 核心模块
- **main.py** - 应用程序入口点,初始化所有系统
- **Start_Run.py** - 启动脚本,设置环境变量和路径
- **core/** - 核心功能模块
- `world.py` - 世界管理器,处理场景渲染和更新
- `selection.py` - 选择系统,处理对象选择
- `event_handler.py` - 事件处理系统
- `tool_manager.py` - 工具管理器
- `script_system.py` - 脚本系统
- `patrol_system.py` - 巡逻系统
- `Command_System.py` - 命令系统
- `terrain_manager.py` - 地形管理
- `vr_manager.py` - VR 功能管理
- `collision_manager.py` - 碰撞检测管理
- `resource_manager.py` - 资源管理
- `assembly_interaction.py` - 装配交互
- `maintenance_gui.py` - 维护界面
- `render_pipeline_utils.py` - 渲染管线工具
- `InfoPanelManager.py` - 信息面板管理
- `CustomMouseController.py` - 自定义鼠标控制器
### GUI 系统
- **gui/gui_manager.py** - GUI管理器处理2D/3D界面元素
- **ui/icon_manager.py** - 图标管理器
### 场景管理
- **scene/scene_manager.py** - 场景管理器,处理模型导入、场景树构建
- **scene/util.py** - 场景工具函数
### 项目管理
- **project/project_manager.py** - 项目管理器,处理项目创建、保存、加载
### 脚本系统
- **scripts/** - 包含各种预定义脚本
- `MoverScript.py` - 移动脚本
- `RotatorScript.py` - 旋转脚本
- `ScalerScript.py` - 缩放脚本
- `ColorChangerScript.py` - 颜色变化脚本
- `FollowerScript.py` - 跟随脚本
- `BouncerScript.py` - 弹跳脚本
- `ComboAnimatorScript.py` - 组合动画脚本
### VR 系统
- **vr_actions/** - VR动作配置
- `actions.json` - VR动作定义
- `bindings_*.json` - 不同VR设备的绑定配置
### 资源管理
- **Resources/** - 资源目录
- `models/` - 3D模型
- `textures/` - 纹理贴图
- `materials/` - 材质文件
- `animations/` - 动画文件
- `icons/` - 图标资源
### 渲染管线
- **RenderPipelineFile/** - 高级渲染管线
- `rpcore/` - 渲染管线核心
- `rpplugins/` - 渲染插件
- `effects/` - 后处理效果
- `config/` - 渲染配置
## 启动和运行
### 环境要求
- Python 3.10.12
- Panda3D 1.10.15
- PyQt5 5.15.9
- OpenVR 2.2.0 (VR功能)
### 运行方式
1. **直接运行主程序**:
```bash
python Start_Run.py
```
2. **带项目路径运行**:
```bash
python Start_Run.py /path/to/project
```
3. **从main.py运行**:
```bash
python main.py
```
### 配置文件
- **config/vr_settings.json** - VR渲染配置
- **imgui.ini** - ImGui界面配置
- **.gitignore** - Git忽略文件配置
## 开发约定
### 代码风格
- 使用UTF-8编码
- 遵循PEP 8代码规范
- 类名使用驼峰命名法
- 函数和变量使用下划线命名法
- 文件头部包含模块说明和导入信息
### 脚本开发
- 所有用户脚本应继承 `ScriptBase`
- 脚本文件放在 `scripts/` 目录下
- 使用 `ScriptManager` 管理脚本生命周期
- 脚本API通过 `world` 对象提供
### 插件开发
- 插件系统支持动态加载
- 插件配置文件使用JSON格式
- 插件应实现标准接口
### VR开发
- VR动作配置在 `vr_actions/actions.json` 中定义
- 支持多种VR设备Vive、Oculus、Index
- VR渲染配置在 `config/vr_settings.json`
## 构建和部署
### 依赖安装
```bash
pip install -r requirements/requirements.txt
```
### 测试
项目包含多个测试脚本:
- `test_quick_script.py` - 快速测试脚本
- `TestMover.py` - 移动测试
- `TestRotator.py` - 旋转测试
- `TestScaler.py` - 缩放测试
### 项目文件
- 项目配置使用JSON格式
- 项目文件包含场景、资源、脚本等信息
- 使用 `ProjectManager` 管理项目生命周期
## 常见问题
### VR相关问题
1. 确保VR设备已正确连接
2. 检查OpenVR运行时是否安装
3. 验证VR动作配置是否正确
### 渲染问题
1. 检查显卡驱动是否最新
2. 确认RenderPipeline配置正确
3. 验证材质和纹理路径
### 性能优化
1. 使用合适的LOD设置
2. 优化场景复杂度
3. 调整渲染质量设置
## 扩展开发
### 添加新脚本
1. 在 `scripts/` 目录创建新脚本文件
2. 继承 `ScriptBase`
3. 实现必要的方法
4. 通过 `ScriptManager` 注册脚本
### 添加新工具
1. 在 `core/tool_manager.py` 中注册新工具
2. 实现工具逻辑
3. 添加GUI界面元素
### 添加新渲染效果
1. 在 `RenderPipelineFile/rpplugins/` 目录创建插件
2. 实现渲染逻辑
3. 添加配置选项
## 联系和支持
- 项目Git仓库: http://10.0.0.99:4000/Rowland/EG.git
- 当前分支: imgui
- 最新提交: 移除qt依赖 (33e62bd1e4c2c8d3aac15e045b419edb8992d7ff)
---
*该文档由iFlow CLI自动生成最后更新时间: 2026年1月28日*

1
EG Submodule

@ -0,0 +1 @@
Subproject commit 69e2bda47e9713705ad5c45a08b6fc643a2b51f6

179
IFLOW.md
View File

@ -1,179 +0,0 @@
# iFlow 上下文文档
## 项目概述
这是一个基于 Panda3D 和 PyQt5 的 3D 虚拟现实 (VR) 应用程序框架。该项目旨在提供一个功能齐全、模块化的 3D 环境,支持 VR 设备(如 HTC Vive, Oculus Rift的集成包含场景管理、模型导入、GUI 系统、脚本系统、地形系统、碰撞检测以及完整的 VR 交互功能。
核心架构围绕 `MyWorld` 类构建,该类继承自 `CoreWorld`并集成了各种管理器模块如选择系统、工具管理器、脚本管理器、GUI 管理器、场景管理器、项目管理器、地形管理器、碰撞管理器和 VR 管理器。
## 核心技术栈
- **核心引擎**: Panda3D
- **图形渲染**: 可选择普通渲染或 RenderPipeline 高级渲染管线
- **VR 支持**: OpenVR/SteamVR
- **用户界面**: PyQt5
- **3D 模型格式**: 支持 glTF, FBX (需转换), BAM 等
- **脚本语言**: Python (内嵌脚本系统)
- **物理/碰撞**: Panda3D 内置碰撞系统
## 项目结构
```
.
├── core/ # 核心模块
│ ├── world.py # CoreWorld 基础世界类
│ ├── vr/ # VR 子模块 (完整模块化结构)
│ │ ├── __init__.py
│ │ ├── config/ # VR 配置管理
│ │ ├── interaction/ # VR 交互系统 (动作、抓取、摇杆、传送)
│ │ ├── performance/ # VR 性能监控
│ │ ├── rendering/ # VR 渲染相关 (RenderPipeline 集成)
│ │ ├── testing/ # VR 测试模式
│ │ ├── tracking/ # VR 设备跟踪
│ │ └── visualization/ # VR 可视化 (控制器模型)
│ ├── vr_manager.py # VR 管理器主文件 (待拆分)
│ ├── selection.py # 选择系统
│ ├── tool_manager.py # 工具管理器
│ ├── script_system.py # 脚本系统
│ ├── gui_manager.py # GUI 管理器
│ ├── terrain_manager.py # 地形管理器
│ ├── collision_manager.py # 碰撞管理器
│ ├── event_handler.py # 事件处理器
│ ├── patrol_system.py # 巡检系统
│ ├── Command_System.py # 命令系统
│ └── InfoPanelManager.py # 信息面板管理器
├── demo/ # 示例和测试文件
├── gui/ # GUI 相关模块
├── project/ # 项目管理模块
├── scene/ # 场景管理模块 (部分代码在 core/)
├── scripts/ # 脚本文件目录
├── ui/ # UI 组件和主窗口
├── QPanda3D/ # Panda3D 与 PyQt 集成库
├── Resources/ # 资源文件 (模型、纹理等)
├── config/ # 配置文件
│ └── vr_settings.json # VR 配置文件
├── main.py # 程序入口点
└── Start_Run.py # 启动脚本
```
## 核心功能模块
### 1. World (core/world.py, main.py)
- `CoreWorld`: 基础 3D 世界设置,包括相机、光照、地面、资源路径。
- `MyWorld`: 扩展的主世界类,整合所有管理器和功能模块。
- **初始化**: 设置资源路径、相机、光照、地面,加载中文字体。
- **兼容性**: 提供旧版属性访问接口。
- **功能代理**: 将大量功能委托给专门的管理器。
### 2. VR 系统 (core/vr/)
这是一个高度模块化的 VR 子系统,核心是 `VRManager` (core/vr_manager.py)。
- **VRManager**:
- **初始化与状态管理**: 检查 VR 可用性、初始化 OpenVR、管理启用/禁用状态。
- **渲染系统**:
- 支持普通渲染和 RenderPipeline 高级渲染两种模式。
- 创建和管理左右眼的渲染缓冲区和相机。
- 实现高效的纹理提交到 OpenVR Compositor。
- 支持动态分辨率缩放和质量预设。
- **跟踪系统**:
- 通过 OpenVR 获取 HMD 和控制器的姿态。
- 使用锚点层级系统 (`tracking_space`, `hmd_anchor` 等) 管理设备位置。
- 坐标系转换 (OpenVR 到 Panda3D)。
- **控制器**:
- `LeftController`, `RightController`: 管理具体的手柄输入和可视化。
- 支持动作系统 (VRActionManager) 或直接输入读取。
- **交互系统**:
- **VRInteractionManager**: 对象抓取和交互。
- **VRTeleportSystem**: 传送功能。
- **VRJoystickManager**: 摇杆移动控制。
- **性能优化**:
- 对象池 (Mat4) 减少 GC 压力。
- 纹理 ID 缓存避免重复 prepare。
- 智能 GPU 同步策略。
- 性能模式自动切换。
- **配置管理**:
- `VRConfigManager`: 从 `config/vr_settings.json` 加载/保存配置。
- **测试与调试**:
- `VRTestMode`: 提供不同的测试显示模式和功能开关。
- `VRPerformanceMonitor`: 性能监控和报告。
### 3. GUI 系统 (core/gui_manager.py, gui/)
- **GUIManager**: 管理 2D 和 3D GUI 元素的创建、编辑、删除。
- **功能**:
- 创建按钮、标签、输入框、2D/3D 图像、视频屏幕等。
- GUI 编辑模式,支持拖拽创建和属性编辑。
- 与场景树和属性面板集成。
- 独立的 GUI 预览窗口。
### 4. 场景与模型管理 (core/scene_manager.py)
- **SceneManager**: 管理 3D 场景中的所有模型。
- **功能**:
- 模型导入 (支持 glTF, FBX 转换)。
- 材质和几何体处理。
- 碰撞体设置。
- 场景保存/加载 (BAM 格式)。
- 场景树更新。
### 5. 脚本系统 (core/script_system.py)
- **ScriptManager**: 嵌入式 Python 脚本系统。
- **功能**:
- 脚本文件的创建、加载、重载。
- 为游戏对象挂载/卸载脚本。
- 热重载支持。
- 脚本信息查询。
### 6. 地形系统 (core/terrain_manager.py)
- **TerrainManager**: 管理 3D 地形。
- **功能**:
- 从高度图或创建平面地形。
- 地形 LOD 更新。
- 地形高度查询和编辑。
### 7. 碰撞系统 (core/collision_manager.py)
- **CollisionManager**: 处理场景中的碰撞检测。
- **功能**:
- 模型间碰撞检测。
- 碰撞历史和统计。
### 8. 工具与选择系统 (core/tool_manager.py, core/selection.py)
- **ToolManager**: 管理当前使用的工具 (选择、移动、旋转、缩放)。
- **SelectionSystem**: 处理对象选择逻辑和相机聚焦。
## 构建与运行
### 入口点
- `main.py`: 主程序入口,创建 `MyWorld` 实例并启动 PyQt5 主窗口。
- `Start_Run.py`: 可能的启动脚本。
### 运行方式
1. 确保已安装所有依赖项Panda3D, PyQt5, OpenVR 等)。
2. 运行 `python main.py` 启动应用程序。
3. 如果连接了 VR 设备并安装了 SteamVR可以在应用内启用 VR 模式。
### 依赖项
项目未提供 `requirements.txt` 文件,但根据代码分析,主要依赖包括:
- `panda3d`
- `PyQt5`
- `openvr` (用于 VR 功能)
- `numpy` (在 VR 模块中使用)
## 开发约定
- **模块化设计**: 功能被分解到不同的管理器类中,`MyWorld` 主要起到集成和代理的作用。
- **VR 子模块化**: VR 功能被组织在 `core/vr/` 目录下,具有清晰的子模块划分。
- **配置驱动**: VR 设置通过 `config/vr_settings.json` 文件进行管理。
- **性能意识**: VR 模块包含大量性能优化措施,如对象池、缓存、智能同步等。
- **向后兼容**: `MyWorld` 通过属性代理保持与旧代码的兼容性。
- **测试模式**: VR 系统包含专门的测试模式,便于调试和验证不同功能。

View File

@ -1,271 +0,0 @@
from panda3d.core import *
from direct.interval.IntervalGlobal import *
class Env_Grid_Maker:
def __init__(self, XYPlaneShow = True, XZPlaneShow = False, YZPlaneShow = False, endCapLinesShow = True, XSize = 50, YSize = 50, ZSize = 50, gridStep = 10, subdiv = 10):
#Create line objects
self.axisLines = LineSegs()
self.gridLines = LineSegs()
self.subdivLines = LineSegs()
#Init passed variables
self.XSize = XSize
self.YSize = YSize
self.ZSize = ZSize
self.gridStep = gridStep
self.subdiv = subdiv
#Init default variables
#Plane and end cap line visibility (1 is show, 0 is hide)
self.XYPlaneShow = XYPlaneShow
self.XZPlaneShow = XZPlaneShow
self.YZPlaneShow = YZPlaneShow
self.endCapLinesShow = endCapLinesShow
#Alpha variables for each plane
#self.XYPlaneAlpha = 1
#self.XZPlaneAlpha = 1
#self.YZPlaneAlpha = 1
#Colors (RGBA passed as a VBase4 object)
self.XAxisColor = VBase4(1, 0, 0, 1)
self.YAxisColor = VBase4(0, 1, 0, 1)
self.ZAxisColor = VBase4(0, 0, 1, 1)
self.gridColor = VBase4(1, 1, 1, 1)
self.subdivColor = VBase4(.35, .35, .35, 1)
#Line thicknesses (in pixels)
self.axisThickness = 3
self.gridThickness = 1
self.subdivThickness = 1
def create(self):
#Set line thicknesses
self.axisLines.setThickness(self.axisThickness)
self.gridLines.setThickness(self.gridThickness)
self.subdivLines.setThickness(self.subdivThickness)
if(self.XSize != 0):
#Draw X axis line
self.axisLines.setColor(self.XAxisColor)
self.axisLines.moveTo(-(self.XSize), 0, 0)
self.axisLines.drawTo(self.XSize, 0, 0)
if(self.YSize != 0):
#Draw Y axis line
self.axisLines.setColor(self.YAxisColor)
self.axisLines.moveTo(0, -(self.YSize), 0)
self.axisLines.drawTo(0, self.YSize, 0)
if(self.ZSize != 0):
#Draw Z axis line
self.axisLines.setColor(self.ZAxisColor)
self.axisLines.moveTo(0, 0, -(self.ZSize))
self.axisLines.drawTo(0, 0, self.ZSize)
#Check to see if primary grid lines should be drawn at all
if(self.gridStep != 0):
#Draw primary grid lines
self.gridLines.setColor(self.gridColor)
#Draw primary grid lines metering x axis if any x-length
if(self.XSize != 0):
if((self.YSize != 0) and (self.XYPlaneShow)):
#Draw y lines across x axis starting from center moving out
#XY Plane
for x in self.myfrange(0, self.XSize, self.gridStep):
self.gridLines.moveTo(x, -(self.YSize), 0)
self.gridLines.drawTo(x, self.YSize, 0)
self.gridLines.moveTo(-x, -(self.YSize), 0)
self.gridLines.drawTo(-x, self.YSize, 0)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(self.XSize, -(self.YSize), 0)
self.gridLines.drawTo(self.XSize, self.YSize, 0)
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
self.gridLines.drawTo(-(self.XSize), self.YSize, 0)
if((self.ZSize != 0) and (self.XZPlaneShow)):
#Draw z lines across x axis starting from center moving out
#XZ Plane
for x in self.myfrange(0, self.XSize, self.gridStep):
self.gridLines.moveTo(x, 0, -(self.ZSize))
self.gridLines.drawTo(x, 0, self.ZSize)
self.gridLines.moveTo(-x, 0, -(self.ZSize))
self.gridLines.drawTo(-x, 0, self.ZSize)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(self.XSize, 0, -(self.ZSize))
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
self.gridLines.drawTo(-(self.XSize), 0, self.ZSize)
#Draw primary grid lines metering y axis if any y-length
if(self.YSize != 0):
if((self.YSize != 0) and (self.XYPlaneShow)):
#Draw x lines across y axis
#XY Plane
for y in self.myfrange(0, self.YSize, self.gridStep):
self.gridLines.moveTo(-(self.XSize), y, 0)
self.gridLines.drawTo(self.XSize, y, 0)
self.gridLines.moveTo(-(self.XSize), -y, 0)
self.gridLines.drawTo(self.XSize, -y, 0)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(-(self.XSize), self.YSize, 0)
self.gridLines.drawTo(self.XSize, self.YSize, 0)
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
self.gridLines.drawTo(self.XSize, -(self.YSize), 0)
if((self.ZSize != 0) and (self.YZPlaneShow)):
#Draw z lines across y axis
#YZ Plane
for y in self.myfrange(0, self.YSize, self.gridStep):
self.gridLines.moveTo(0, y, -(self.ZSize))
self.gridLines.drawTo(0, y, self.ZSize)
self.gridLines.moveTo(0, -y, -(self.ZSize))
self.gridLines.drawTo(0, -y, self.ZSize)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(0, self.YSize, -(self.ZSize))
self.gridLines.drawTo(0, self.YSize, self.ZSize)
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
self.gridLines.drawTo(0, -(self.YSize), self.ZSize)
#Draw primary grid lines metering z axis if any z-length
if(self.ZSize != 0):
if((self.XSize != 0) and (self.XZPlaneShow)):
#Draw x lines across z axis
#XZ Plane
for z in self.myfrange(0, self.ZSize, self.gridStep):
self.gridLines.moveTo(-(self.XSize), 0, z)
self.gridLines.drawTo(self.XSize, 0, z)
self.gridLines.moveTo(-(self.XSize), 0, -z)
self.gridLines.drawTo(self.XSize, 0, -z)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(-(self.XSize), 0, self.ZSize)
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
self.gridLines.drawTo(self.XSize, 0, -(self.ZSize))
if((self.YSize != 0) and (self.YZPlaneShow)):
#Draw y lines across z axis
#YZ Plane
for z in self.myfrange(0, self.ZSize, self.gridStep):
self.gridLines.moveTo(0, -(self.YSize), z)
self.gridLines.drawTo(0, self.YSize, z)
self.gridLines.moveTo(0, -(self.YSize), -z)
self.gridLines.drawTo(0, self.YSize, -z)
if(self.endCapLinesShow):
#Draw endcap lines
self.gridLines.moveTo(0, -(self.YSize), self.ZSize)
self.gridLines.drawTo(0, self.YSize, self.ZSize)
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
self.gridLines.drawTo(0, self.YSize, -(self.ZSize))
#Check to see if secondary grid lines should be drawn
if(self.subdiv != 0):
#Draw secondary grid lines
self.subdivLines.setColor(self.subdivColor)
if(self.XSize != 0):
adjustedstep = self.gridStep / self.subdiv
if((self.YSize != 0) and (self.XYPlaneShow)):
#Draw y lines across x axis starting from center moving out
#XY
for x in self.myfrange(0, self.XSize, adjustedstep):
self.subdivLines.moveTo(x, -(self.YSize), 0)
self.subdivLines.drawTo(x, self.YSize, 0)
self.subdivLines.moveTo(-x, -(self.YSize), 0)
self.subdivLines.drawTo(-x, self.YSize, 0)
if((self.ZSize != 0) and (self.XZPlaneShow)):
#Draw z lines across x axis starting from center moving out
#XZ
for x in self.myfrange(0, self.XSize, adjustedstep):
self.subdivLines.moveTo(x, 0, -(self.ZSize))
self.subdivLines.drawTo(x, 0, self.ZSize)
self.subdivLines.moveTo(-x, 0, -(self.ZSize))
self.subdivLines.drawTo(-x, 0, self.ZSize)
if(self.YSize != 0):
if((self.YSize != 0) and (self.XYPlaneShow)):
#Draw x lines across y axis
#XY
for y in self.myfrange(0, self.YSize, adjustedstep):
self.subdivLines.moveTo(-(self.XSize), y, 0)
self.subdivLines.drawTo(self.XSize, y, 0)
self.subdivLines.moveTo(-(self.XSize), -y, 0)
self.subdivLines.drawTo(self.XSize, -y, 0)
if((self.ZSize != 0) and (self.YZPlaneShow)):
#Draw z lines across y axis
#YZ
for y in self.myfrange(0, self.YSize, adjustedstep):
self.subdivLines.moveTo(0, y, -(self.ZSize))
self.subdivLines.drawTo(0, y, self.ZSize)
self.subdivLines.moveTo(0, -y, -(self.ZSize))
self.subdivLines.drawTo(0, -y, self.ZSize)
if(self.ZSize != 0):
if((self.XSize != 0) and (self.XZPlaneShow)):
#Draw x lines across z axis
#XZ
for z in self.myfrange(0, self.ZSize, adjustedstep):
self.subdivLines.moveTo(-(self.XSize), 0, z)
self.subdivLines.drawTo(self.XSize, 0, z)
self.subdivLines.moveTo(-(self.XSize), 0, -z)
self.subdivLines.drawTo(self.XSize, 0, -z)
if((self.YSize != 0) and (self.YZPlaneShow)):
#Draw y lines across z axis
#YZ
for z in self.myfrange(0, self.ZSize, adjustedstep):
self.subdivLines.moveTo(0, -(self.YSize), z)
self.subdivLines.drawTo(0, self.YSize, z)
self.subdivLines.moveTo(0, -(self.YSize), -z)
self.subdivLines.drawTo(0, self.YSize, -z)
#Create ThreeAxisGrid nodes and nodepaths
#Create parent node and path
self.parentNode = PandaNode('threeaxisgrid-parentnode')
self.parentNodePath = NodePath(self.parentNode)
#Create axis lines node and path, then reparent
self.axisLinesNode = self.axisLines.create()
self.axisLinesNodePath = NodePath(self.axisLinesNode)
self.axisLinesNodePath.reparentTo(self.parentNodePath)
#Create grid lines node and path, then reparent
self.gridLinesNode = self.gridLines.create()
self.gridLinesNodePath = NodePath(self.gridLinesNode)
self.gridLinesNodePath.reparentTo(self.parentNodePath)
#Create subdivision lines node and path then reparent
self.subdivLinesNode = self.subdivLines.create()
self.subdivLinesNodePath = NodePath(self.subdivLinesNode)
self.subdivLinesNodePath.reparentTo(self.parentNodePath)
return self.parentNodePath
def myfrange(self, start, stop=None, step=None):
if stop is None:
stop = float(start)
start = 0.0
if step is None:
step = 1.0
cur = float(start)
while cur < stop:
yield cur
cur += step

View File

@ -1,2 +0,0 @@
name="QMeta3D"
__all__ = ["Env_Grid_Maker"]

View File

@ -1,192 +0,0 @@
import sys
import os
from core.CustomMouseController import CustomMouseController
# 获取 RenderPipelineFile 的路径
render_pipeline_path = './RenderPipelineFile'
# 将该路径添加到 sys.path 中,确保 Python 能够找到它
project_root = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, project_root)
sys.path.insert(0, render_pipeline_path)
from RenderPipelineFile.rpcore import RenderPipeline
_global_render_pipeline = None
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from panda3d.core import *
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
from direct.showbase.ShowBase import ShowBase
import platform
from QMeta3D.QMouseWatcherNode import QMouseWatcherNode
from RenderPipelineFile.rpcore.render_target import RenderTarget
__all__ = ["Meta3DWorld"]
_global_world_instance=None
import builtins
class Meta3DWorld(ShowBase):
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
name="qMeta3D"):
global _global_world_instance
global _global_render_pipeline
_global_world_instance = self
sort = -100
self.parent = None
# 设置基本配置
loadPrcFileData("", "show-frame-rate-meter 0")
loadPrcFileData("", "window-type offscreen") # 设置为离屏渲染
loadPrcFileData("", f"win-size {width} {height}")
loadPrcFileData("", "win-fixed-size #f") # 允许窗口调整大小
# 🚀 VR性能优化配置
loadPrcFileData("", "prefer-single-buffer true") # 减少缓冲区交换开销
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
loadPrcFileData("", "sync-video false") # 禁用默认VSync让OpenVR控制
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
loadPrcFileData("", "clock-mode non-real-time")
# loadPrcFileData("", "gl-debug true")
if (is_fullscreen):
loadPrcFileData("", "fullscreen #t")
self.render_pipeline = RenderPipeline()
self.render_pipeline.pre_showbase_init()
ShowBase.__init__(self)
# 初始化渲染管线并设置可调整大小的标志
self.render_pipeline.create(self)
_global_render_pipeline = self.render_pipeline
# 创建 Qt 能读的 RGBA8 贴图
self.qt_output_tex = Texture("qt_output_tex")
self.qt_output_tex.set_format(Texture.F_rgba8)
self.qt_output_tex.set_component_type(Texture.T_unsigned_byte)
# # 获取图形管线对象
# gsg = self.win.getGsg()
# host = gsg.getEngine().getHost()
self.win.add_render_texture(self.qt_output_tex, GraphicsOutput.RTM_copy_ram)
#self.screenTexture = Texture()
#self.screenTexture.setMinfilter(Texture.FTLinear)
#self.screenTexture.setFormat(Texture.FRgba32)
#self.screenTexture.set_wrap_u(Texture.WM_clamp)
#self.screenTexture.set_wrap_v(Texture.WM_clamp)
# buff_size_x = int(self.win.get_x_size() * size)
# buff_size_y = int(self.win.get_y_size() * size)
# winprops = WindowProperties()
# winprops.set_size(buff_size_x, buff_size_y)
#
#
# props = FrameBufferProperties()
# props.set_rgb_color(True)
# props.set_rgba_bits(8, 8, 8, 8)
# props.set_depth_bits(8)
# self.buff = self.graphicsEngine.make_output(
# self.pipe, name, sort,
# props, winprops,
# GraphicsPipe.BF_resizeable,
# self.win.get_gsg(), self.win)
#self.screenTexture = render_pipeline._final_stage.target.color_tex
#self.buff.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
# self.buff.set_sort(sort)
#self.cam = self.makeCamera(self.buff)
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
#self.render_pipeline._showbase.camera.reparentTo(self.render)
#base.camera.reparentTo(self.render)
#self.cam.reparentTo(self.render) # 可选同步
#render_pipeline.set_camera(self.cam)
#添加渲染效果
#self.cam = self.render_pipeline._showbase.cam
#self.camNode = self.cam.node()
#self.camLens = self.camNode.get_lens()
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
#self.render_pipeline.daytime_mgr.update()
# if clear_color is None:
# self.buff.set_clear_active(GraphicsOutput.RTPColor, False)
# else:
# self.buff.set_clear_color(clear_color)
# self.buff.set_clear_active(GraphicsOutput.RTPColor, True)
# self.disableMouse()
self.mouse_controller = CustomMouseController(self)
self.mouse_controller.setUp()
# 添加错误处理钩子
self.accept("transform_state_error", self._handle_transform_error)
def _handle_transform_error(self):
"""处理TransformState相关的错误"""
try:
from panda3d.core import TransformState, RenderState
TransformState.clear_cache()
RenderState.clear_cache()
print("已清理TransformState和RenderState缓存")
except Exception as e:
print(f"清理缓存时出错: {e}")
def render_pipeline(self):
"""获取 RenderPipeline 实例"""
return self._render_pipeline
def set_parent(self, parent: QWidget):
self.parent = parent
self.mouseWatcherNode = QMouseWatcherNode(parent)
def getAspectRatio(self, win = None):
if win is None and self.parent is not None:
return float(self.parent.width()) / float(self.parent.height())
else:
return super().getAspectRatio(win)
def get_render_pipeline():
"""获取全局 RenderPipeline 单例"""
if _global_render_pipeline is None:
raise RuntimeError(
"RenderPipeline has not been initialized yet. Please create a 3DWorld instance first.")
return _global_render_pipeline
def resize_buffer(self, width: int, height: int):
props = WindowProperties()
props.set_size(width, height)
self.win.request_properties(props)
# 重新分配输出贴图的大小
self.qt_output_tex.set_x_size(width)
self.qt_output_tex.set_y_size(height)
# 更新 lens 的 aspect ratio
if self.camLens:
self.camLens.set_film_size(width, height) # 或 set_aspect_ratio(width / height)
# 强制更新窗口(有时在 Qt 内嵌时需要)
self.graphicsEngine.open_windows()

View File

@ -1,252 +0,0 @@
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from direct.task.TaskManagerGlobal import taskMgr
from QMeta3D.QMeta3D_Buttons_Translation import QMeta3D_Button_translation
from QMeta3D.QMeta3D_Keys_Translation import QMeta3D_Key_translation
from QMeta3D.QMeta3D_Modifiers_Translation import QMeta3D_Modifier_translation
__all__ = ["QMeta3DWidget"]
class QMeta3DSynchronizer(QTimer):
def __init__(self, qMeta3DWidget, FPS=60):
QTimer.__init__(self)
self.qMeta3DWidget = qMeta3DWidget
dt = 1000 / FPS
self.setInterval(int(dt))
self.timeout.connect(self.tick)
def tick(self):
try:
# 在渲染前清理可能损坏的TransformState对象
from panda3d.core import TransformState
TransformState.clear_cache()
taskMgr.step()
self.qMeta3DWidget.update()
except AssertionError as e:
# 专门处理 TransformState has_mat() 断言错误
if "has_mat" in str(e):
print(f"警告: 检测到TransformState断言错误已静默处理: {e}")
# 尝试恢复渲染状态
try:
# 强制清理缓存并重试
from panda3d.core import TransformState, RenderState
TransformState.clear_cache()
RenderState.clear_cache()
taskMgr.step()
self.qMeta3DWidget.update()
except:
pass
else:
# 重新抛出其他断言错误
raise
except Exception as e:
# 静默处理其他所有异常
print(f"警告: 检测到异常,已静默处理: {e}")
def get_panda_key_modifiers(evt):
panda_mods = []
qt_mods = evt.modifiers()
for qt_mod, panda_mod in QMeta3D_Modifier_translation.items():
if (qt_mods & qt_mod) == qt_mod:
panda_mods.append(panda_mod)
return panda_mods
def get_panda_key_modifiers_prefix(evt):
# join all modifiers (except NoModifier, which is None) with '-'
prefix = "-".join([mod for mod in get_panda_key_modifiers(evt) if mod is not None])
# if the prefix is not empty, append a '-'
if prefix:
prefix += '-'
return prefix
class QMeta3DWidget(QWidget):
def __init__(self, Meta3DWorld, parent=None, FPS=60, debug=False):
QWidget.__init__(self, parent)
self.rp_sync_requested = False
# set fixed geometry
self.Meta3DWorld = Meta3DWorld
self.Meta3DWorld.set_parent(self)
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
# pandaTimer = QTimer(self)
# pandaTimer.timeout.connect()
# pandaTimer.start(0)
self.setFocusPolicy(Qt.StrongFocus)
# Setup another timer that redraws this widget in a specific FPS
# redrawTimer = QTimer(self)
# redrawTimer.timeout.connect(self.update)
# redrawTimer.start(1000/FPS)
self.paintSurface = QPainter()
self.rotate = QTransform()
self.rotate.rotate(180)
self.out_image = QImage()
size = self.Meta3DWorld.cam.node().get_lens().get_film_size()
self.initial_film_size = QSizeF(size.x, size.y)
self.initial_size = self.size()
self.synchronizer = QMeta3DSynchronizer(self, FPS)
self.synchronizer.start()
self.debug = debug
def mousePressEvent(self, evt):
button = evt.button()
try:
b = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
if self.debug:
print(b)
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
except:
print("Unimplemented button. Please send an issue on github to fix this problem")
def mouseMoveEvent(self, evt:QtGui.QMouseEvent):
button = evt.button()
try:
b = "mouse-move"
if self.debug:
print(b)
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
except:
print("Unimplemented button. Please send an issue on github to fix this problem")
def mouseReleaseEvent(self, evt):
button = evt.button()
try:
b = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
if self.debug:
print(b)
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
except:
print("Unimplemented button. Please send an issue on github to fix this problem")
def wheelEvent(self, evt):
delta = evt.angleDelta().y()
try:
if self.debug:
print(f"wheel {delta}")
messenger.send('wheel',[{"delta":delta}])
except:
print("Unimplemented button. Please send an issue on github to fix this problem")
def keyPressEvent(self, evt):
key = evt.key()
try:
k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
if self.debug:
print(k)
messenger.send(k)
except:
print("Unimplemented key. Please send an issue on github to fix this problem")
def keyReleaseEvent(self, evt):
key = evt.key()
try:
k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
if self.debug:
print(k)
messenger.send(k)
except:
print("Unimplemented key. Please send an issue on github to fix this problem")
def resizeEvent(self, evt):
width = evt.size().width()
height = evt.size().height()
#print(f"width:{width}")
#print(f"height:{height}")
from Meta3DWorld import resize_buffer
lens = self.Meta3DWorld.cam.node().get_lens()
def minimumSizeHint(self):
return QSize(400, 300)
def paintEvent(self, event):
tex = self.Meta3DWorld.qt_output_tex
gsg = base.win.getGsg()
if not gsg:
self.update()
return
if not tex.hasRamImage():
base.graphicsEngine.extractTextureData(tex, gsg)
self.update()
return
data = tex.getRamImage().getData()
tex_width = tex.getXSize()
tex_height = tex.getYSize()
expected_len = tex_width * tex_height * 4
if len(data) != expected_len:
print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
self.update()
return
img = QImage(data, tex_width, tex_height, QImage.Format_ARGB32).mirrored()
widget_width = self.width()
widget_height = self.height()
painter = QPainter(self)
# 【保持宽高比的缩放】
scaled_img = img.scaled(widget_width, widget_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
# 居中绘制
x_offset = (widget_width - scaled_img.width()) // 2
y_offset = (widget_height - scaled_img.height()) // 2
painter.drawImage(x_offset, y_offset, scaled_img)
painter.end()
def sync_Meta3d_window_size(self, width, height):
try:
from panda3d.core import WindowProperties, LVecBase2i
# 确保尺寸是4的倍数RenderPipeline 要求)
adjusted_width = width - width % 4
adjusted_height = height - height % 4
# 更新窗口属性
props = WindowProperties()
props.setSize(adjusted_width, adjusted_height)
# 对于 offscreen 渲染,直接更新窗口属性
if self.Meta3DWorld.win:
self.Meta3DWorld.win.request_properties(props)
# 手动触发 RenderPipeline 的尺寸更新逻辑
if hasattr(self.Meta3DWorld, 'render_pipeline'):
# 更新全局分辨率
from RenderPipelineFile.rpcore.globals import Globals
Globals.native_resolution = LVecBase2i(adjusted_width, adjusted_height)
# 重新计算渲染分辨率
self.Meta3DWorld.render_pipeline._compute_render_resolution()
# 通知各个管理器处理尺寸变化
self.Meta3DWorld.render_pipeline.light_mgr.compute_tile_size()
self.Meta3DWorld.render_pipeline.stage_mgr.handle_window_resize()
if hasattr(self.Meta3DWorld.render_pipeline, 'debugger'):
self.Meta3DWorld.render_pipeline.debugger.handle_window_resize()
# 触发插件的窗口尺寸变化钩子
self.Meta3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
except Exception as e:
print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")

View File

@ -1,43 +0,0 @@
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
__all__ = ["QMeta3D_Keys_Translation.py"]
QMeta3D_Button_translation ={
Qt.NoButton:'',
Qt.AllButtons:'unknown',
Qt.LeftButton:'mouse1',
Qt.RightButton:'mouse2',
Qt.MidButton:'mouse3',
Qt.MiddleButton:'mouse3',
Qt.BackButton:'unknown',
Qt.XButton1:'unknown',
Qt.ExtraButton1:'unknown',
Qt.ForwardButton:'unknown',
Qt.XButton2:'unknown',
Qt.ExtraButton2:'unknown',
Qt.TaskButton:'unknown',
Qt.ExtraButton3:'unknown',
Qt.ExtraButton4:'unknown',
Qt.ExtraButton5:'unknown',
Qt.ExtraButton6:'unknown',
Qt.ExtraButton7:'unknown',
Qt.ExtraButton8:'unknown',
Qt.ExtraButton9:'unknown',
Qt.ExtraButton10:'unknown',
Qt.ExtraButton11:'unknown',
Qt.ExtraButton12:'unknown',
Qt.ExtraButton13:'unknown',
Qt.ExtraButton14:'unknown',
Qt.ExtraButton15:'unknown',
Qt.ExtraButton16:'unknown',
Qt.ExtraButton17:'unknown',
Qt.ExtraButton18:'unknown',
Qt.ExtraButton19:'unknown',
Qt.ExtraButton20:'unknown',
Qt.ExtraButton21:'unknown',
Qt.ExtraButton22:'unknown',
Qt.ExtraButton23:'unknown',
Qt.ExtraButton24:'unknown',
}

View File

@ -1,477 +0,0 @@
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
__all__ = ["QMeta3D_Keys_Translation.py"]
QMeta3D_Key_translation ={
Qt.Key_0:'0',
Qt.Key_1:'1',
Qt.Key_2:'2',
Qt.Key_3:'3',
Qt.Key_4:'4',
Qt.Key_5:'5',
Qt.Key_6:'6',
Qt.Key_7:'7',
Qt.Key_8:'8',
Qt.Key_9:'9',
Qt.Key_A:'a',
Qt.Key_AE:'ae',
Qt.Key_Aacute:'unknown',
Qt.Key_Acircumflex:'unknown',
Qt.Key_AddFavorite:'unknown',
Qt.Key_Adiaeresis:'unknown',
Qt.Key_Agrave:'unknown',
Qt.Key_Alt:'lalt',
Qt.Key_AltGr:'unknown',
Qt.Key_Ampersand:'unknown',
Qt.Key_Any:'unknown',
Qt.Key_Apostrophe:'unknown',
Qt.Key_ApplicationLeft:'unknown',
Qt.Key_ApplicationRight:'unknown',
Qt.Key_Aring:'unknown',
Qt.Key_AsciiCircum:'unknown',
Qt.Key_AsciiTilde:'unknown',
Qt.Key_Asterisk:'unknown',
Qt.Key_At:'unknown',
Qt.Key_Atilde:'unknown',
Qt.Key_AudioCycleTrack:'unknown',
Qt.Key_AudioForward:'unknown',
Qt.Key_AudioRandomPlay:'unknown',
Qt.Key_AudioRepeat:'unknown',
Qt.Key_AudioRewind:'unknown',
Qt.Key_Away:'unknown',
Qt.Key_B:'b',
Qt.Key_Back:'unknown',
Qt.Key_BackForward:'unknown',
Qt.Key_Backslash:'unknown',
Qt.Key_Backspace:'unknown',
Qt.Key_Backtab:'unknown',
Qt.Key_Bar:'unknown',
Qt.Key_BassBoost:'unknown',
Qt.Key_BassDown:'unknown',
Qt.Key_BassUp:'unknown',
Qt.Key_Battery:'unknown',
Qt.Key_Blue:'unknown',
Qt.Key_Bluetooth:'unknown',
Qt.Key_Book:'unknown',
Qt.Key_BraceLeft:'unknown',
Qt.Key_BraceRight:'unknown',
Qt.Key_BracketLeft:'unknown',
Qt.Key_BracketRight:'unknown',
Qt.Key_BrightnessAdjust:'unknown',
Qt.Key_C:'c',
Qt.Key_CD:'unknown',
Qt.Key_Calculator:'unknown',
Qt.Key_Calendar:'unknown',
Qt.Key_Call:'unknown',
Qt.Key_Camera:'unknown',
Qt.Key_CameraFocus:'unknown',
Qt.Key_Cancel:'unknown',
Qt.Key_CapsLock:'unknown',
Qt.Key_Ccedilla:'unknown',
Qt.Key_ChannelDown:'unknown',
Qt.Key_ChannelUp:'unknown',
Qt.Key_Clear:'unknown',
Qt.Key_ClearGrab:'unknown',
Qt.Key_Close:'unknown',
Qt.Key_Codeinput:'unknown',
Qt.Key_Colon:'unknown',
Qt.Key_Comma:'unknown',
Qt.Key_Community:'unknown',
Qt.Key_Context1:'unknown',
Qt.Key_Context2:'unknown',
Qt.Key_Context3:'unknown',
Qt.Key_Context4:'unknown',
Qt.Key_ContrastAdjust:'unknown',
Qt.Key_Control:'control',
Qt.Key_Copy:'unknown',
Qt.Key_Cut:'unknown',
Qt.Key_D:'d',
Qt.Key_DOS:'unknown',
Qt.Key_Dead_A:'unknown',
Qt.Key_Dead_Abovecomma:'unknown',
Qt.Key_Dead_Abovedot:'unknown',
Qt.Key_Dead_Abovereversedcomma:'unknown',
Qt.Key_Dead_Abovering:'unknown',
Qt.Key_Dead_Aboveverticalline:'unknown',
Qt.Key_Dead_Acute:'unknown',
Qt.Key_Dead_Belowbreve:'unknown',
Qt.Key_Dead_Belowcircumflex:'unknown',
Qt.Key_Dead_Belowcomma:'unknown',
Qt.Key_Dead_Belowdiaeresis:'unknown',
Qt.Key_Dead_Belowdot:'unknown',
Qt.Key_Dead_Belowmacron:'unknown',
Qt.Key_Dead_Belowring:'unknown',
Qt.Key_Dead_Belowtilde:'unknown',
Qt.Key_Dead_Belowverticalline:'unknown',
Qt.Key_Dead_Breve:'unknown',
Qt.Key_Dead_Capital_Schwa:'unknown',
Qt.Key_Dead_Caron:'unknown',
Qt.Key_Dead_Cedilla:'unknown',
Qt.Key_Dead_Circumflex:'unknown',
Qt.Key_Dead_Currency:'unknown',
Qt.Key_Dead_Diaeresis:'unknown',
Qt.Key_Dead_Doubleacute:'unknown',
Qt.Key_Dead_Doublegrave:'unknown',
Qt.Key_Dead_E:'unknown',
Qt.Key_Dead_Grave:'unknown',
Qt.Key_Dead_Greek:'unknown',
Qt.Key_Dead_Hook:'unknown',
Qt.Key_Dead_Horn:'unknown',
Qt.Key_Dead_I:'unknown',
Qt.Key_Dead_Invertedbreve:'unknown',
Qt.Key_Dead_Iota:'unknown',
Qt.Key_Dead_Longsolidusoverlay:'unknown',
Qt.Key_Dead_Lowline:'unknown',
Qt.Key_Dead_Macron:'unknown',
Qt.Key_Dead_O:'unknown',
Qt.Key_Dead_Ogonek:'unknown',
Qt.Key_Dead_Semivoiced_Sound:'unknown',
Qt.Key_Dead_Small_Schwa:'unknown',
Qt.Key_Dead_Stroke:'unknown',
Qt.Key_Dead_Tilde:'unknown',
Qt.Key_Dead_U:'unknown',
Qt.Key_Dead_Voiced_Sound:'unknown',
Qt.Key_Dead_a:'unknown',
Qt.Key_Dead_e:'unknown',
Qt.Key_Dead_i:'unknown',
Qt.Key_Dead_o:'unknown',
Qt.Key_Dead_u:'unknown',
Qt.Key_Delete:'delete',
Qt.Key_Direction_L:'unknown',
Qt.Key_Direction_R:'unknown',
Qt.Key_Display:'unknown',
Qt.Key_Documents:'unknown',
Qt.Key_Dollar:'unknown',
Qt.Key_Down:'arrow_down',
Qt.Key_E:'e',
Qt.Key_ETH:'unknown',
Qt.Key_Eacute:'unknown',
Qt.Key_Ecircumflex:'unknown',
Qt.Key_Ediaeresis:'unknown',
Qt.Key_Egrave:'unknown',
Qt.Key_Eisu_Shift:'unknown',
Qt.Key_Eisu_toggle:'unknown',
Qt.Key_Eject:'unknown',
Qt.Key_End:'unknown',
Qt.Key_Enter:'unknown',
Qt.Key_Equal:'unknown',
Qt.Key_Escape:'escape',
Qt.Key_Excel:'unknown',
Qt.Key_Exclam:'unknown',
Qt.Key_Execute:'unknown',
Qt.Key_Exit:'unknown',
Qt.Key_Explorer:'unknown',
Qt.Key_F:'f',
Qt.Key_F1:'f1',
Qt.Key_F10:'f10',
Qt.Key_F11:'f11',
Qt.Key_F12:'f12',
Qt.Key_F13:'f13',
Qt.Key_F14:'f14',
Qt.Key_F15:'f15',
Qt.Key_F16:'f16',
Qt.Key_F17:'f17',
Qt.Key_F18:'f18',
Qt.Key_F19:'unknown',
Qt.Key_F2:'unknown',
Qt.Key_F20:'unknown',
Qt.Key_F21:'unknown',
Qt.Key_F22:'unknown',
Qt.Key_F23:'unknown',
Qt.Key_F24:'unknown',
Qt.Key_F25:'unknown',
Qt.Key_F26:'unknown',
Qt.Key_F27:'unknown',
Qt.Key_F28:'unknown',
Qt.Key_F29:'unknown',
Qt.Key_F3:'f3',
Qt.Key_F30:'unknown',
Qt.Key_F31:'unknown',
Qt.Key_F32:'unknown',
Qt.Key_F33:'unknown',
Qt.Key_F34:'unknown',
Qt.Key_F35:'unknown',
Qt.Key_F4:'f4',
Qt.Key_F5:'f5',
Qt.Key_F6:'f6',
Qt.Key_F7:'f7',
Qt.Key_F8:'f8',
Qt.Key_F9:'f9',
Qt.Key_Favorites:'unknown',
Qt.Key_Finance:'unknown',
Qt.Key_Find:'unknown',
Qt.Key_Flip:'unknown',
Qt.Key_Forward:'unknown',
Qt.Key_G:'g',
Qt.Key_Game:'unknown',
Qt.Key_Go:'unknown',
Qt.Key_Greater:'unknown',
Qt.Key_Green:'unknown',
Qt.Key_Guide:'unknown',
Qt.Key_H:'h',
Qt.Key_Hangul:'unknown',
Qt.Key_Hangul_Banja:'unknown',
Qt.Key_Hangul_End:'unknown',
Qt.Key_Hangul_Hanja:'unknown',
Qt.Key_Hangul_Jamo:'unknown',
Qt.Key_Hangul_Jeonja:'unknown',
Qt.Key_Hangul_PostHanja:'unknown',
Qt.Key_Hangul_PreHanja:'unknown',
Qt.Key_Hangul_Romaja:'unknown',
Qt.Key_Hangul_Special:'unknown',
Qt.Key_Hangul_Start:'unknown',
Qt.Key_Hangup:'unknown',
Qt.Key_Hankaku:'unknown',
Qt.Key_Help:'unknown',
Qt.Key_Henkan:'unknown',
Qt.Key_Hibernate:'unknown',
Qt.Key_Hiragana:'unknown',
Qt.Key_Hiragana_Katakana:'unknown',
Qt.Key_History:'unknown',
Qt.Key_Home:'home',
Qt.Key_HomePage:'unknown',
Qt.Key_HotLinks:'unknown',
Qt.Key_Hyper_L:'unknown',
Qt.Key_Hyper_R:'unknown',
Qt.Key_I:'i',
Qt.Key_Iacute:'unknown',
Qt.Key_Icircumflex:'unknown',
Qt.Key_Idiaeresis:'unknown',
Qt.Key_Igrave:'unknown',
Qt.Key_Info:'unknown',
Qt.Key_Insert:'unknown',
Qt.Key_J:'j',
Qt.Key_K:'k',
Qt.Key_Kana_Lock:'unknown',
Qt.Key_Kana_Shift:'unknown',
Qt.Key_Kanji:'unknown',
Qt.Key_Katakana:'unknown',
Qt.Key_KeyboardBrightnessDown:'unknown',
Qt.Key_KeyboardBrightnessUp:'unknown',
Qt.Key_KeyboardLightOnOff:'unknown',
Qt.Key_L:'l',
Qt.Key_LastNumberRedial:'unknown',
Qt.Key_Launch0:'unknown',
Qt.Key_Launch1:'unknown',
Qt.Key_Launch2:'unknown',
Qt.Key_Launch3:'unknown',
Qt.Key_Launch4:'unknown',
Qt.Key_Launch5:'unknown',
Qt.Key_Launch6:'unknown',
Qt.Key_Launch7:'unknown',
Qt.Key_Launch8:'unknown',
Qt.Key_Launch9:'unknown',
Qt.Key_LaunchA:'unknown',
Qt.Key_LaunchB:'unknown',
Qt.Key_LaunchC:'unknown',
Qt.Key_LaunchD:'unknown',
Qt.Key_LaunchE:'unknown',
Qt.Key_LaunchF:'unknown',
Qt.Key_LaunchG:'unknown',
Qt.Key_LaunchH:'unknown',
Qt.Key_LaunchMail:'unknown',
Qt.Key_LaunchMedia:'unknown',
Qt.Key_Left:'arrow_left',
Qt.Key_Less:'unknown',
Qt.Key_LightBulb:'unknown',
Qt.Key_LogOff:'unknown',
Qt.Key_M:'m',
Qt.Key_MailForward:'unknown',
Qt.Key_Market:'unknown',
Qt.Key_Massyo:'unknown',
Qt.Key_MediaLast:'unknown',
Qt.Key_MediaNext:'unknown',
Qt.Key_MediaPause:'unknown',
Qt.Key_MediaPlay:'unknown',
Qt.Key_MediaPrevious:'unknown',
Qt.Key_MediaRecord:'unknown',
Qt.Key_MediaStop:'unknown',
Qt.Key_MediaTogglePlayPause:'unknown',
Qt.Key_Meeting:'unknown',
Qt.Key_Memo:'unknown',
Qt.Key_Menu:'unknown',
Qt.Key_MenuKB:'unknown',
Qt.Key_MenuPB:'unknown',
Qt.Key_Messenger:'unknown',
Qt.Key_Meta:'unknown',
Qt.Key_MicMute:'unknown',
Qt.Key_MicVolumeDown:'unknown',
Qt.Key_MicVolumeUp:'unknown',
Qt.Key_Minus:'unknown',
Qt.Key_Mode_switch:'unknown',
Qt.Key_MonBrightnessDown:'unknown',
Qt.Key_MonBrightnessUp:'unknown',
Qt.Key_Muhenkan:'unknown',
Qt.Key_Multi_key:'unknown',
Qt.Key_MultipleCandidate:'unknown',
Qt.Key_Music:'unknown',
Qt.Key_MySites:'unknown',
Qt.Key_N:'n',
Qt.Key_New:'unknown',
Qt.Key_News:'unknown',
Qt.Key_No:'unknown',
Qt.Key_Ntilde:'unknown',
Qt.Key_NumLock:'unknown',
Qt.Key_NumberSign:'unknown',
Qt.Key_O:'o',
Qt.Key_Oacute:'unknown',
Qt.Key_Ocircumflex:'unknown',
Qt.Key_Odiaeresis:'unknown',
Qt.Key_OfficeHome:'unknown',
Qt.Key_Ograve:'unknown',
Qt.Key_Ooblique:'unknown',
Qt.Key_Open:'unknown',
Qt.Key_OpenUrl:'unknown',
Qt.Key_Option:'unknown',
Qt.Key_Otilde:'unknown',
Qt.Key_P:'p',
Qt.Key_PageDown:'unknown',
Qt.Key_PageUp:'unknown',
Qt.Key_ParenLeft:'unknown',
Qt.Key_ParenRight:'unknown',
Qt.Key_Paste:'unknown',
Qt.Key_Pause:'unknown',
Qt.Key_Percent:'unknown',
Qt.Key_Period:'unknown',
Qt.Key_Phone:'unknown',
Qt.Key_Pictures:'unknown',
Qt.Key_Play:'unknown',
Qt.Key_Plus:'unknown',
Qt.Key_PowerDown:'unknown',
Qt.Key_PowerOff:'unknown',
Qt.Key_PreviousCandidate:'unknown',
Qt.Key_Print:'unknown',
Qt.Key_Printer:'unknown',
Qt.Key_Q:'q',
Qt.Key_Question:'unknown',
Qt.Key_QuoteDbl:'unknown',
Qt.Key_QuoteLeft:'unknown',
Qt.Key_R:'r',
Qt.Key_Red:'unknown',
Qt.Key_Redo:'unknown',
Qt.Key_Refresh:'unknown',
Qt.Key_Reload:'unknown',
Qt.Key_Reply:'unknown',
Qt.Key_Return:'unknown',
Qt.Key_Right:'arrow_right',
Qt.Key_Romaji:'unknown',
Qt.Key_RotateWindows:'unknown',
Qt.Key_RotationKB:'unknown',
Qt.Key_RotationPB:'unknown',
Qt.Key_S:'s',
Qt.Key_Save:'unknown',
Qt.Key_ScreenSaver:'unknown',
Qt.Key_ScrollLock:'unknown',
Qt.Key_Search:'unknown',
Qt.Key_Select:'unknown',
Qt.Key_Semicolon:'unknown',
Qt.Key_Send:'unknown',
Qt.Key_Settings:'unknown',
Qt.Key_Shift:'unknown',
Qt.Key_Shop:'unknown',
Qt.Key_SingleCandidate:'unknown',
Qt.Key_Slash:'unknown',
Qt.Key_Sleep:'unknown',
Qt.Key_Space:'space',
Qt.Key_Spell:'unknown',
Qt.Key_SplitScreen:'unknown',
Qt.Key_Standby:'unknown',
Qt.Key_Stop:'unknown',
Qt.Key_Subtitle:'unknown',
Qt.Key_Super_L:'unknown',
Qt.Key_Super_R:'unknown',
Qt.Key_Support:'unknown',
Qt.Key_Suspend:'unknown',
Qt.Key_SysReq:'unknown',
Qt.Key_T:'t',
Qt.Key_THORN:'unknown',
Qt.Key_Tab:'unknown',
Qt.Key_TaskPane:'unknown',
Qt.Key_Terminal:'unknown',
Qt.Key_Time:'unknown',
Qt.Key_ToDoList:'unknown',
Qt.Key_ToggleCallHangup:'unknown',
Qt.Key_Tools:'unknown',
Qt.Key_TopMenu:'unknown',
Qt.Key_TouchpadOff:'unknown',
Qt.Key_TouchpadOn:'unknown',
Qt.Key_TouchpadToggle:'unknown',
Qt.Key_Touroku:'unknown',
Qt.Key_Travel:'unknown',
Qt.Key_TrebleDown:'unknown',
Qt.Key_TrebleUp:'unknown',
Qt.Key_U:'u',
Qt.Key_UWB:'unknown',
Qt.Key_Uacute:'unknown',
Qt.Key_Ucircumflex:'unknown',
Qt.Key_Udiaeresis:'unknown',
Qt.Key_Ugrave:'unknown',
Qt.Key_Underscore:'unknown',
Qt.Key_Undo:'unknown',
Qt.Key_Up:'arrow_up',
Qt.Key_V:'v',
Qt.Key_Video:'unknown',
Qt.Key_View:'unknown',
Qt.Key_VoiceDial:'unknown',
Qt.Key_VolumeDown:'unknown',
Qt.Key_VolumeMute:'unknown',
Qt.Key_VolumeUp:'unknown',
Qt.Key_W:'w',
Qt.Key_WLAN:'unknown',
Qt.Key_WWW:'unknown',
Qt.Key_WakeUp:'unknown',
Qt.Key_WebCam:'unknown',
Qt.Key_Word:'unknown',
Qt.Key_X:'x',
Qt.Key_Xfer:'unknown',
Qt.Key_Y:'y',
Qt.Key_Yacute:'unknown',
Qt.Key_Yellow:'unknown',
Qt.Key_Yes:'unknown',
Qt.Key_Z:'z',
Qt.Key_Zenkaku:'unknown',
Qt.Key_Zenkaku_Hankaku:'unknown',
Qt.Key_Zoom:'unknown',
Qt.Key_ZoomIn:'unknown',
Qt.Key_ZoomOut:'unknown',
Qt.Key_acute:'unknown',
Qt.Key_brokenbar:'unknown',
Qt.Key_cedilla:'unknown',
Qt.Key_cent:'unknown',
Qt.Key_copyright:'unknown',
Qt.Key_currency:'unknown',
Qt.Key_degree:'unknown',
Qt.Key_diaeresis:'unknown',
Qt.Key_division:'unknown',
Qt.Key_exclamdown:'unknown',
Qt.Key_guillemotleft:'unknown',
Qt.Key_guillemotright:'unknown',
Qt.Key_hyphen:'unknown',
Qt.Key_iTouch:'unknown',
Qt.Key_macron:'unknown',
Qt.Key_masculine:'unknown',
Qt.Key_mu:'unknown',
Qt.Key_multiply:'unknown',
Qt.Key_nobreakspace:'unknown',
Qt.Key_notsign:'unknown',
Qt.Key_onehalf:'unknown',
Qt.Key_onequarter:'unknown',
Qt.Key_onesuperior:'unknown',
Qt.Key_ordfeminine:'unknown',
Qt.Key_paragraph:'unknown',
Qt.Key_periodcentered:'unknown',
Qt.Key_plusminus:'unknown',
Qt.Key_questiondown:'unknown',
Qt.Key_registered:'unknown',
Qt.Key_section:'unknown',
Qt.Key_ssharp:'unknown',
Qt.Key_sterling:'unknown',
Qt.Key_threequarters:'unknown',
Qt.Key_threesuperior:'unknown',
Qt.Key_twosuperior:'unknown',
Qt.Key_unknown:'unknown',
Qt.Key_ydiaeresis:'unknown',
Qt.Key_yen:'unknown',
}

View File

@ -1,15 +0,0 @@
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
__all__ = ["QMeta3D_Modifiers_Translation.py"]
QMeta3D_Modifier_translation ={
Qt.NoModifier:None,
Qt.ShiftModifier:'shift',
Qt.ControlModifier:'control',
Qt.AltModifier:'alt',
Qt.MetaModifier:'unknown',
Qt.KeypadModifier:'unknown',
Qt.GroupSwitchModifier:'unknown',
}

View File

@ -1,27 +0,0 @@
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from panda3d.core import *
__all__ = ["QMouseWatcherNode"]
class QMouseWatcherNode(MouseWatcher):
def __init__(self, parent):
super().__init__()
self.parent = parent
def getMouse(self, *args, **kwargs):
pos = self.parent.mapFromGlobal(QCursor.pos())
rel_x = -1 + 2 * pos.x() / self.parent.width()
rel_y = -1 + 2 * pos.y() / self.parent.height()
rel_y = -rel_y
return LPoint2(rel_x, rel_y)
def hasMouse(self):
return isinstance(self.parent, QWidget)

View File

@ -1,2 +0,0 @@
name="QMeta3D"
__all__ = ["generate_qt_to_pd3d_translator"]

View File

@ -1,11 +0,0 @@
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
H=Qt.__dict__
lst = [a for a in H if a.startswith("Key_")]
QMeta3D_Key_translation = "QMeta3D_Key_translation ={"
for i in range(len(lst)):
QMeta3D_Key_translation += "Qt.{}:'unknown',\n".format(lst[i])
QMeta3D_Key_translation += "}"
print(QMeta3D_Key_translation)

View File

@ -1,2 +0,0 @@
name="QMeta3D"
__all__ = ["QMeta3DWidget.py", "Meta3DWorld.py", "QMeta3D_Keys_Translation.py"]

View File

@ -1,12 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<list>
<option value="PyQt5-stubs==5.15.6.0" />
</list>
</option>
</inspection_tool>
</profile>
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<list>
<option value="PyQt5-stubs==5.15.6.0" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@ -1,6 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -0,0 +1,174 @@
# This is the config file used to configure basic settings for Panda3D.
# The pipeline loads it at startup to ensure the environment is setup properly.
# -------------- Development options --------------
pstats-gpu-timing #t
gl-debug #t
gl-debug-object-labels #t
# -------------- Production options ---------------
# pstats-gpu-timing #f
# gl-debug #f
# gl-debug-object-labels #f
# ----------------- Misc Settings -----------------
# Disable V-Sync
sync-video #f
# Limit the pstats-rate. This causes huge lag on windows 10.
pstats-max-rate 200
# No stack trace on assertion, set this to true to make panda crash on assertions
# (which will allow to debug it)
# assert-abort #t
# show-dll-error-dialog #f
# File system should be case sensitive
# NOTICE: Set this to #f if you are using tempfile, since it returns
# wrong cased directory paths
vfs-case-sensitive #t
# Enable state cache, this seems to actually help the performance by a lot
state-cache #t
transform-cache #t
# Hide frame rate meter (we have our own)
show-frame-rate-meter #f
# Set text settings
text-minfilter linear
text-magfilter linear
text-page-size 512 512
text-rwap-mode WM_border_clor
# Better text performance since rdb's patch
text-flatten 0
text-dynamic-merge 1
# For smoother animations
# even-animation #t
# Threading, really buggy!
#threading-model App/Cull/Draw
# Disable stencil, not supported/required
support-stencil #f
framebuffer-stencil #f
# Don't use srgb correction, we do that in the final shader
framebuffer-srgb #f
# Don't use multisamples
framebuffer-multisample #f
multisamples 0
# Don't rescale textures which are no power-of-2
textures-power-2 none
# Set default texture filters
texture-anisotropic-degree 16
texture-magfilter linear
texture-minfilter linear
texture-quality-level fastest
# Enable seamless cubemap filtering, important for environment filtering
gl-cube-map-seamless #t
# Disable caching of textures
model-cache-textures #f
# Disable the annoying SRGB warning from pnmimage
notify-level-pnmimage error
# Disable the buffer viewer, we have our own
show-buffers #f
# Use the default coordinate system, this makes our matrix transformations
# faster because we don't have have to transform them to a different coordinate
# system before
gl-coordinate-system default
# This makes animations smoother, especially if they were exported at 30 FPS
# and are played at 60 FPS
interpolate-frames #t
# Disable workarround in panda which causes our shadow atlas to take twice
# the amount of vram it should, due to an intel driver bug.
gl-force-fbo-color #f
# ----------- OpenGL / Performance Settings ------------
# Require OpenGL 4.3 at least, necessary for Intel drivers on Linux
gl-version 4 3
# Animations on the gpu. The default shader has to get adjusted to support this
# feature before this option can be turned on.
# hardware-animated-vertices #t
# Try this options for performance
# uniquify-matrix #t
# uniquify-transforms #t
# uniquify-states #t
# uniquify-attribs #f
# Enable garbarge collection
garbage-collect-states #t
# garbage-collect-states-rate 0.2
# Compress textures on the drivers?
# driver-compress-textures #t
# Faster animations? (Have to test)
# matrix-palette #t
# display-list-animation #t
# Better GL performance by not using gl-finish and so on
gl-finish #f
gl-force-no-error #t
gl-check-errors #f
gl-force-no-flush #t
gl-force-no-scissor #t
# Eventually disable memory barriers, have to check if this is faster
gl-enable-memory-barriers #f
# Disable threading
lock-to-one-cpu #t
support-threads #f
# Let the driver generate the mipmaps
driver-generate-mipmaps #t
# Use immutable texture storage, it is *supposed* to be faster, but might not be
# XXX: Seems to produce an GL_INVALID_VALUE when disabled
gl-immutable-texture-storage #t
# Default window settings
# depth-bits 0
color-bits 0
framebuffer-depth #f
# Small performance gain by specifying fixed vertex attribute locations.
# Might cause issues with some (incorrectly converted/loaded) meshes though
gl-fixed-vertex-attrib-locations #f
# Disable the fragment shader performance warning
gl-validate-shaders #f
gl-skip-shader-recompilation-warnings #t
alpha-scale-via-texture #f
pstats-name Render Pipeline Stats
rescale-normals #f
screenshot-extension png
# Required for correct velocity
always-store-prev-transform #t
allow-incomplete-render #t
no-singular-invert #f

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,5 @@
# This file stores internal settings of the pipeline. It does not contain the
# plugin settings, but just the basic settings of the internal pipeline components.
pipeline:
@ -6,12 +8,12 @@ pipeline:
# it will also disable the hotkeys, and give a small performance boost.
# Most likely you also don't want to show it in your own game, so set
# it to false in that case.
display_debugger: False
display_debugger: true
# Affects which debugging information is displayed. If this is set to false,
# only frame time is displayed, otherwise much more information is visible.
# Has no effect when display_debugger is set to false.
advanced_debugging_info: False
advanced_debugging_info: true
# Whether to use the GL_R11F_G11F_B10F texture format to save memory
# and bandwidth. Usually you want to enable this, however it can
@ -75,8 +77,8 @@ shadows:
# getting updated fast enough. However, this also affects the performance
# quite a bit, since for every shadow map a part of the scene has
# to get re-rendered.
max_updates: 16
max_updates: 8
# Sets the maximum distance until which shadows are updated. If a shadow
# source is further away, it will no longer recieve updates
max_update_distance: 300.0
max_update_distance: 150.0

View File

@ -7,7 +7,6 @@ enabled:
- ao
- bloom
- color_correction
- env_probes
- forward_shading
- motion_blur
- pssm
@ -16,16 +15,17 @@ enabled:
- sky_ao
- smaa
- ssr
- clouds
#- dof
#- fxaa
#- volumetrics
#- vxgi
# - clouds
# - dof
- env_probes
# - fxaa
# - volumetrics
# - vxgi
overrides:
ao:
blur_quality: LOW
blur_quality: MEDIUM
blur_normal_factor: 2.97
blur_depth_factor: 0.88158
occlusion_strength: 2.19
@ -87,10 +87,10 @@ overrides:
sharpen_twice: False
dof:
focal_point: 5
focal_size: 1
blur_strength: 1
near_blur_strength: 1
focal_point: 1000.0
focal_size: 994.0
blur_strength: 0.0
near_blur_strength: 0.4286
env_probes:
probe_resolution: 128

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
material:
name: GroundMaterial
base_color: "../Textures/ground_diffuse.png"
normal: "../Textures/ground_normal.png"
roughness: 0.8
metallic: 0.0
two_sided: true
material:
name: GroundMaterial
base_color: "../Textures/ground_diffuse.png"
normal: "../Textures/ground_normal.png"
roughness: 0.8
metallic: 0.0
two_sided: true

View File

@ -1,47 +1,47 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
示例脚本 - 演示如何编写脚本
"""
from core.script_system import ScriptBase
class ExampleScript(ScriptBase):
"""示例脚本类"""
def __init__(self):
super().__init__()
self.counter = 0
self.rotation_speed = 30.0 # 度/秒
def start(self):
"""脚本开始时调用"""
self.log("示例脚本开始运行!")
self.log(f"挂载到对象: {self.gameObject.getName()}")
def update(self, dt):
"""每帧更新"""
self.counter += 1
# 每60帧输出一次信息
if self.counter % 60 == 0:
self.log(f"运行了 {self.counter}")
# 让对象旋转
if self.transform:
current_h = self.transform.getH()
new_h = current_h + self.rotation_speed * dt
self.transform.setH(new_h)
def on_destroy(self):
"""脚本销毁时调用"""
self.log("示例脚本被销毁")
def on_enable(self):
"""脚本启用时调用"""
self.log("示例脚本被启用")
def on_disable(self):
"""脚本禁用时调用"""
self.log("示例脚本被禁用")
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
示例脚本 - 演示如何编写脚本
"""
from core.script_system import ScriptBase
class ExampleScript(ScriptBase):
"""示例脚本类"""
def __init__(self):
super().__init__()
self.counter = 0
self.rotation_speed = 30.0 # 度/秒
def start(self):
"""脚本开始时调用"""
self.log("示例脚本开始运行!")
self.log(f"挂载到对象: {self.gameObject.getName()}")
def update(self, dt):
"""每帧更新"""
self.counter += 1
# 每60帧输出一次信息
if self.counter % 60 == 0:
self.log(f"运行了 {self.counter}")
# 让对象旋转
if self.transform:
current_h = self.transform.getH()
new_h = current_h + self.rotation_speed * dt
self.transform.setH(new_h)
def on_destroy(self):
"""脚本销毁时调用"""
self.log("示例脚本被销毁")
def on_enable(self):
"""脚本启用时调用"""
self.log("示例脚本被启用")
def on_disable(self):
"""脚本禁用时调用"""
self.log("示例脚本被禁用")

View File

@ -1,35 +1,35 @@
# Debug metallic texture effect
# This effect visualizes metallic texture directly for debugging
fragment:
defines: |
#define DEBUG_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Debug: Show metallic texture directly
#if DEBUG_METALLIC_TEXTURE
// Sample metallic from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// For debugging: show texture value as colored visualization
// Blue tint for non-metallic, yellow tint for metallic
vec3 debug_color = mix(vec3(0.2, 0.2, 1.0), vec3(1.0, 1.0, 0.2), sampled_metallic);
// Apply to material
m.basecolor = debug_color; // Show texture as color for debugging
m.roughness = 0.5; // Fixed roughness for clear visualization
m.metallic = sampled_metallic; // Also apply to metallic
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Fallback
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Debug metallic texture effect
# This effect visualizes metallic texture directly for debugging
fragment:
defines: |
#define DEBUG_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Debug: Show metallic texture directly
#if DEBUG_METALLIC_TEXTURE
// Sample metallic from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// For debugging: show texture value as colored visualization
// Blue tint for non-metallic, yellow tint for metallic
vec3 debug_color = mix(vec3(0.2, 0.2, 1.0), vec3(1.0, 1.0, 0.2), sampled_metallic);
// Apply to material
m.basecolor = debug_color; // Show texture as color for debugging
m.roughness = 0.5; // Fixed roughness for clear visualization
m.metallic = sampled_metallic; // Also apply to metallic
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Fallback
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,35 +1,35 @@
# Debug roughness texture effect
# This effect visualizes roughness texture directly for debugging
fragment:
defines: |
#define DEBUG_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture
material: |
// Debug: Show roughness texture directly
#if DEBUG_ROUGHNESS_TEXTURE
// Sample roughness from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// For debugging: show texture value as grayscale color
// This helps verify the texture is being read correctly
vec3 debug_color = vec3(sampled_roughness);
// Apply to material
m.basecolor = debug_color; // Show texture as color for debugging
m.roughness = sampled_roughness; // Also apply to roughness
m.metallic = 0.0; // Keep metallic low for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Fallback
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Debug roughness texture effect
# This effect visualizes roughness texture directly for debugging
fragment:
defines: |
#define DEBUG_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture
material: |
// Debug: Show roughness texture directly
#if DEBUG_ROUGHNESS_TEXTURE
// Sample roughness from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// For debugging: show texture value as grayscale color
// This helps verify the texture is being read correctly
vec3 debug_color = vec3(sampled_roughness);
// Apply to material
m.basecolor = debug_color; // Show texture as color for debugging
m.roughness = sampled_roughness; // Also apply to roughness
m.metallic = 0.0; // Keep metallic low for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Fallback
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,39 +1,39 @@
# Metallic-only PBR effect
# This effect specifically handles metallic textures correctly
# Ensures metallic texture is not confused with diffuse texture
fragment:
defines: |
#define USE_METALLIC_TEXTURE_ONLY 1
#define DONT_FETCH_DEFAULT_TEXTURES 0
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture only
material: |
// Only handle metallic texture, ignore others to avoid confusion
#if USE_METALLIC_TEXTURE_ONLY
// Sample metallic from p3d_Texture5
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Direct control: texture value directly controls metallic
// This gives Blender-like behavior where texture has full control
m.metallic = sampled_metallic;
// Clamp to valid range
m.metallic = clamp(m.metallic, 0.0, 1.0);
// Keep other properties from material (no texture interference)
m.basecolor = mInput.color; // Use material color, not texture
m.roughness = mInput.roughness;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#else
// Fallback to material values only
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Metallic-only PBR effect
# This effect specifically handles metallic textures correctly
# Ensures metallic texture is not confused with diffuse texture
fragment:
defines: |
#define USE_METALLIC_TEXTURE_ONLY 1
#define DONT_FETCH_DEFAULT_TEXTURES 0
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture only
material: |
// Only handle metallic texture, ignore others to avoid confusion
#if USE_METALLIC_TEXTURE_ONLY
// Sample metallic from p3d_Texture5
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Direct control: texture value directly controls metallic
// This gives Blender-like behavior where texture has full control
m.metallic = sampled_metallic;
// Clamp to valid range
m.metallic = clamp(m.metallic, 0.0, 1.0);
// Keep other properties from material (no texture interference)
m.basecolor = mInput.color; // Use material color, not texture
m.roughness = mInput.roughness;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#else
// Fallback to material values only
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,29 +1,29 @@
# PBR effect with additive metallic texture control
# This effect adds metallic texture values to material metallic values
# Final metallic = material_metallic + texture_value (clamped to 0-1)
fragment:
defines: |
#define USE_ADDITIVE_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (additive control)
material: |
// Additive metallic texture control
#if USE_ADDITIVE_METALLIC_TEXTURE
// Sample metallic value from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Add texture value to material metallic value
// This allows enhancing existing metallic areas
m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0);
// Debug: This mode is useful for:
// - Adding metallic details to non-metallic materials
// - Enhancing existing metallic areas
// - Creating metallic highlights on top of base material
#else
// Fallback to material metallic value
m.metallic = mInput.metallic;
#endif
# PBR effect with additive metallic texture control
# This effect adds metallic texture values to material metallic values
# Final metallic = material_metallic + texture_value (clamped to 0-1)
fragment:
defines: |
#define USE_ADDITIVE_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (additive control)
material: |
// Additive metallic texture control
#if USE_ADDITIVE_METALLIC_TEXTURE
// Sample metallic value from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Add texture value to material metallic value
// This allows enhancing existing metallic areas
m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0);
// Debug: This mode is useful for:
// - Adding metallic details to non-metallic materials
// - Enhancing existing metallic areas
// - Creating metallic highlights on top of base material
#else
// Fallback to material metallic value
m.metallic = mInput.metallic;
#endif

View File

@ -1,29 +1,29 @@
# PBR effect with direct metallic texture control
# This effect allows metallic textures to directly control metallic values
# instead of multiplying with material metallic value
fragment:
defines: |
#define USE_DIRECT_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (direct control)
material: |
// Direct metallic texture control
#if USE_DIRECT_METALLIC_TEXTURE
// Sample metallic value directly from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Use texture value directly instead of multiplying
// This allows the texture to have full control over metallic values
m.metallic = sampled_metallic;
// Debug: Ensure we're using the texture value
// White areas = 1.0 (fully metallic)
// Gray areas = 0.5 (semi-metallic)
// Black areas = 0.0 (non-metallic)
#else
// Fallback to material metallic value
m.metallic = mInput.metallic;
#endif
# PBR effect with direct metallic texture control
# This effect allows metallic textures to directly control metallic values
# instead of multiplying with material metallic value
fragment:
defines: |
#define USE_DIRECT_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (direct control)
material: |
// Direct metallic texture control
#if USE_DIRECT_METALLIC_TEXTURE
// Sample metallic value directly from texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Use texture value directly instead of multiplying
// This allows the texture to have full control over metallic values
m.metallic = sampled_metallic;
// Debug: Ensure we're using the texture value
// White areas = 1.0 (fully metallic)
// Gray areas = 0.5 (semi-metallic)
// Black areas = 0.0 (non-metallic)
#else
// Fallback to material metallic value
m.metallic = mInput.metallic;
#endif

View File

@ -1,38 +1,38 @@
# PBR effect with direct roughness texture control
# This effect allows roughness textures to directly control roughness values
# instead of multiplying with material roughness value
fragment:
defines: |
#define USE_DIRECT_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture (direct control)
material: |
// Direct roughness texture control
#if USE_DIRECT_ROUGHNESS_TEXTURE
// Sample roughness value directly from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Use texture value directly instead of multiplying
// This allows the texture to have full control over roughness values
m.roughness = sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
// Debug: Ensure we're using the texture value
// White areas = 1.0 (fully rough)
// Gray areas = 0.5 (semi-rough)
// Black areas = 0.01 (smooth, but not zero to avoid issues)
#else
// Fallback to material roughness value
m.roughness = mInput.roughness;
#endif
// Keep all other properties unchanged for stability
m.basecolor = mInput.color;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
# PBR effect with direct roughness texture control
# This effect allows roughness textures to directly control roughness values
# instead of multiplying with material roughness value
fragment:
defines: |
#define USE_DIRECT_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture (direct control)
material: |
// Direct roughness texture control
#if USE_DIRECT_ROUGHNESS_TEXTURE
// Sample roughness value directly from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Use texture value directly instead of multiplying
// This allows the texture to have full control over roughness values
m.roughness = sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
// Debug: Ensure we're using the texture value
// White areas = 1.0 (fully rough)
// Gray areas = 0.5 (semi-rough)
// Black areas = 0.01 (smooth, but not zero to avoid issues)
#else
// Fallback to material roughness value
m.roughness = mInput.roughness;
#endif
// Keep all other properties unchanged for stability
m.basecolor = mInput.color;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;

View File

@ -1,51 +1,51 @@
# Extended PBR effect with support for additional texture types
# This effect supports metallic, emission, AO, detail, and gloss textures
fragment:
defines: |
#define USE_EXTENDED_TEXTURES 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
uniform sampler2D p3d_Texture6; // Emission texture
uniform sampler2D p3d_Texture7; // AO texture
uniform sampler2D p3d_Texture8; // Alpha texture
uniform sampler2D p3d_Texture9; // Detail texture
uniform sampler2D p3d_Texture10; // Gloss texture
material: |
#if USE_EXTENDED_TEXTURES
// Metallic texture (p3d_Texture5)
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
m.metallic = mInput.metallic * sampled_metallic;
// Emission texture (p3d_Texture6)
vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz;
if (mInput.shading_model == SHADING_MODEL_EMISSIVE) {
m.basecolor += sampled_emission * 2.0; // Boost emission intensity
}
// AO texture (p3d_Texture7) - multiply with base color
float sampled_ao = texture(p3d_Texture7, texcoord).x;
m.basecolor *= sampled_ao;
// Alpha texture (p3d_Texture8) - for transparency
float sampled_alpha = texture(p3d_Texture8, texcoord).x;
if (mInput.shading_model == SHADING_MODEL_TRANSPARENT) {
// Apply alpha testing
if (sampled_alpha < 0.5) discard;
}
// Detail texture (p3d_Texture9) - blend with base color
vec3 sampled_detail = texture(p3d_Texture9, texcoord * 4.0).xyz; // Tiled detail
m.basecolor = mix(m.basecolor, m.basecolor * sampled_detail, 0.5);
// Gloss texture (p3d_Texture10) - affects roughness
float sampled_gloss = texture(p3d_Texture10, texcoord).x;
m.roughness = m.roughness * (1.0 - sampled_gloss); // Gloss is inverse of roughness
#else
// Standard behavior when extended textures are not used
m.metallic = mInput.metallic;
#endif
# Extended PBR effect with support for additional texture types
# This effect supports metallic, emission, AO, detail, and gloss textures
fragment:
defines: |
#define USE_EXTENDED_TEXTURES 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
uniform sampler2D p3d_Texture6; // Emission texture
uniform sampler2D p3d_Texture7; // AO texture
uniform sampler2D p3d_Texture8; // Alpha texture
uniform sampler2D p3d_Texture9; // Detail texture
uniform sampler2D p3d_Texture10; // Gloss texture
material: |
#if USE_EXTENDED_TEXTURES
// Metallic texture (p3d_Texture5)
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
m.metallic = mInput.metallic * sampled_metallic;
// Emission texture (p3d_Texture6)
vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz;
if (mInput.shading_model == SHADING_MODEL_EMISSIVE) {
m.basecolor += sampled_emission * 2.0; // Boost emission intensity
}
// AO texture (p3d_Texture7) - multiply with base color
float sampled_ao = texture(p3d_Texture7, texcoord).x;
m.basecolor *= sampled_ao;
// Alpha texture (p3d_Texture8) - for transparency
float sampled_alpha = texture(p3d_Texture8, texcoord).x;
if (mInput.shading_model == SHADING_MODEL_TRANSPARENT) {
// Apply alpha testing
if (sampled_alpha < 0.5) discard;
}
// Detail texture (p3d_Texture9) - blend with base color
vec3 sampled_detail = texture(p3d_Texture9, texcoord * 4.0).xyz; // Tiled detail
m.basecolor = mix(m.basecolor, m.basecolor * sampled_detail, 0.5);
// Gloss texture (p3d_Texture10) - affects roughness
float sampled_gloss = texture(p3d_Texture10, texcoord).x;
m.roughness = m.roughness * (1.0 - sampled_gloss); // Gloss is inverse of roughness
#else
// Standard behavior when extended textures are not used
m.metallic = mInput.metallic;
#endif

View File

@ -1,19 +1,19 @@
# PBR effect with emission texture support
# This effect extends the default PBR pipeline to support emission textures
fragment:
defines: |
#define USE_EMISSION_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture6; // Emission texture
material: |
// Fetch emission value from texture if available
#if USE_EMISSION_TEXTURE
vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz;
// For emissive materials, add the texture emission to the base color
if (mInput.shading_model == SHADING_MODEL_EMISSIVE) {
m.basecolor += sampled_emission * 2.0; // Boost emission intensity
}
#endif
# PBR effect with emission texture support
# This effect extends the default PBR pipeline to support emission textures
fragment:
defines: |
#define USE_EMISSION_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture6; // Emission texture
material: |
// Fetch emission value from texture if available
#if USE_EMISSION_TEXTURE
vec3 sampled_emission = texture(p3d_Texture6, texcoord).xyz;
// For emissive materials, add the texture emission to the base color
if (mInput.shading_model == SHADING_MODEL_EMISSIVE) {
m.basecolor += sampled_emission * 2.0; // Boost emission intensity
}
#endif

View File

@ -1,40 +1,40 @@
# PBR effect with metallic texture support
# This effect extends the default PBR pipeline to support metallic textures
# Provides both multiplicative and direct control modes
fragment:
defines: |
#define USE_METALLIC_TEXTURE 1
#define METALLIC_CONTROL_MODE 0 // 0=multiply, 1=direct, 2=additive
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Add metallic texture support to the default material processing
// Note: Don't override the default material processing, just extend it
#if USE_METALLIC_TEXTURE
// Sample metallic texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Apply metallic texture based on control mode
#if METALLIC_CONTROL_MODE == 0
// Multiplicative mode (original behavior)
m.metallic = mInput.metallic * sampled_metallic;
#elif METALLIC_CONTROL_MODE == 1
// Direct control mode
m.metallic = sampled_metallic;
#elif METALLIC_CONTROL_MODE == 2
// Additive mode
m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0);
#else
// Fallback to multiplicative
m.metallic = mInput.metallic * sampled_metallic;
#endif
// Ensure valid range
m.metallic = clamp(m.metallic, 0.0, 1.0);
#endif
// Note: Other material properties (basecolor, roughness, etc.) are handled by the default template
// We don't override them here to avoid conflicts
# PBR effect with metallic texture support
# This effect extends the default PBR pipeline to support metallic textures
# Provides both multiplicative and direct control modes
fragment:
defines: |
#define USE_METALLIC_TEXTURE 1
#define METALLIC_CONTROL_MODE 0 // 0=multiply, 1=direct, 2=additive
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Add metallic texture support to the default material processing
// Note: Don't override the default material processing, just extend it
#if USE_METALLIC_TEXTURE
// Sample metallic texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Apply metallic texture based on control mode
#if METALLIC_CONTROL_MODE == 0
// Multiplicative mode (original behavior)
m.metallic = mInput.metallic * sampled_metallic;
#elif METALLIC_CONTROL_MODE == 1
// Direct control mode
m.metallic = sampled_metallic;
#elif METALLIC_CONTROL_MODE == 2
// Additive mode
m.metallic = clamp(mInput.metallic + sampled_metallic, 0.0, 1.0);
#else
// Fallback to multiplicative
m.metallic = mInput.metallic * sampled_metallic;
#endif
// Ensure valid range
m.metallic = clamp(m.metallic, 0.0, 1.0);
#endif
// Note: Other material properties (basecolor, roughness, etc.) are handled by the default template
// We don't override them here to avoid conflicts

View File

@ -1,31 +1,31 @@
# PBR effect with normal mapping support
# This effect ensures proper material color handling when only normal maps are applied
fragment:
defines: |
#define USE_NORMAL_MAPPING_ONLY 1
material: |
// Handle normal mapping without requiring diffuse texture
#if USE_NORMAL_MAPPING_ONLY
// Use material color directly, don't multiply with sampled_diffuse
// This prevents the black color issue when no diffuse texture is present
m.basecolor = mInput.color;
// Handle other textures normally if they exist
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
// Ensure minimum roughness
m.roughness = max(m.roughness, 0.01);
#else
// Standard material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
#endif
m.shading_model_param0 = mInput.arbitrary0;
# PBR effect with normal mapping support
# This effect ensures proper material color handling when only normal maps are applied
fragment:
defines: |
#define USE_NORMAL_MAPPING_ONLY 1
material: |
// Handle normal mapping without requiring diffuse texture
#if USE_NORMAL_MAPPING_ONLY
// Use material color directly, don't multiply with sampled_diffuse
// This prevents the black color issue when no diffuse texture is present
m.basecolor = mInput.color;
// Handle other textures normally if they exist
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
// Ensure minimum roughness
m.roughness = max(m.roughness, 0.01);
#else
// Standard material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
#endif
m.shading_model_param0 = mInput.arbitrary0;

View File

@ -1,33 +1,33 @@
# Stable PBR effect with roughness texture support
# Simplified version to avoid rendering issues and flickering
fragment:
defines: |
#define USE_STABLE_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture only
material: |
// Simple and stable roughness texture handling
#if USE_STABLE_ROUGHNESS_TEXTURE
// Sample roughness from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Use simple multiplication - stable and predictable
// This ensures the texture effect is always visible
m.roughness = mInput.roughness * sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
#else
// Fallback to material roughness
m.roughness = mInput.roughness;
#endif
// Keep all other properties unchanged for stability
m.basecolor = mInput.color;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
# Stable PBR effect with roughness texture support
# Simplified version to avoid rendering issues and flickering
fragment:
defines: |
#define USE_STABLE_ROUGHNESS_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture only
material: |
// Simple and stable roughness texture handling
#if USE_STABLE_ROUGHNESS_TEXTURE
// Sample roughness from texture
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Use simple multiplication - stable and predictable
// This ensures the texture effect is always visible
m.roughness = mInput.roughness * sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
#else
// Fallback to material roughness
m.roughness = mInput.roughness;
#endif
// Keep all other properties unchanged for stability
m.basecolor = mInput.color;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;

View File

@ -1,37 +1,37 @@
# Enhanced PBR effect with metallic texture support
# This effect extends the default PBR to support metallic textures
# Avoids redeclaring textures that are already in the base template
fragment:
defines: |
#define USE_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (not in default template)
material: |
// Enhanced material with metallic texture support
#if USE_METALLIC_TEXTURE
// Sample metallic texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Apply all material properties
// Use the sampled values from the base template for other textures
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic * sampled_metallic; // Now with metallic texture support!
// Ensure valid ranges
m.roughness = max(m.roughness, 0.01);
m.metallic = clamp(m.metallic, 0.0, 1.0);
#else
// Fallback to standard material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic; // No metallic texture
#endif
m.shading_model_param0 = mInput.arbitrary0;
# Enhanced PBR effect with metallic texture support
# This effect extends the default PBR to support metallic textures
# Avoids redeclaring textures that are already in the base template
fragment:
defines: |
#define USE_METALLIC_TEXTURE 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture (not in default template)
material: |
// Enhanced material with metallic texture support
#if USE_METALLIC_TEXTURE
// Sample metallic texture
float sampled_metallic = texture(p3d_Texture5, texcoord).x;
// Apply all material properties
// Use the sampled values from the base template for other textures
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic * sampled_metallic; // Now with metallic texture support!
// Ensure valid ranges
m.roughness = max(m.roughness, 0.01);
m.metallic = clamp(m.metallic, 0.0, 1.0);
#else
// Fallback to standard material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic; // No metallic texture
#endif
m.shading_model_param0 = mInput.arbitrary0;

View File

@ -1,39 +1,39 @@
# Roughness-only PBR effect
# This effect specifically handles roughness textures correctly
# Ensures roughness texture is not confused with diffuse texture
fragment:
defines: |
#define USE_ROUGHNESS_TEXTURE_ONLY 1
#define DONT_FETCH_DEFAULT_TEXTURES 0
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture only
material: |
// Only handle roughness texture, ignore others to avoid confusion
#if USE_ROUGHNESS_TEXTURE_ONLY
// Sample roughness from p3d_Texture3
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Apply roughness: material_roughness * texture_value
// This gives Blender-like behavior
m.roughness = mInput.roughness * sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
// Keep other properties from material (no texture interference)
m.basecolor = mInput.color; // Use material color, not texture
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#else
// Fallback to material values only
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Roughness-only PBR effect
# This effect specifically handles roughness textures correctly
# Ensures roughness texture is not confused with diffuse texture
fragment:
defines: |
#define USE_ROUGHNESS_TEXTURE_ONLY 1
#define DONT_FETCH_DEFAULT_TEXTURES 0
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture only
material: |
// Only handle roughness texture, ignore others to avoid confusion
#if USE_ROUGHNESS_TEXTURE_ONLY
// Sample roughness from p3d_Texture3
float sampled_roughness = texture(p3d_Texture3, texcoord).x;
// Apply roughness: material_roughness * texture_value
// This gives Blender-like behavior
m.roughness = mInput.roughness * sampled_roughness;
// Ensure minimum roughness to avoid rendering issues
m.roughness = max(m.roughness, 0.01);
// Keep other properties from material (no texture interference)
m.basecolor = mInput.color; // Use material color, not texture
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#else
// Fallback to material values only
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,31 +1,31 @@
# 最简单的纹理测试效果
# 直接将纹理显示为颜色,验证纹理是否被正确读取
fragment:
defines: |
#define SIMPLE_TEXTURE_TEST 1
inout: |
uniform sampler2D p3d_Texture3; // 粗糙度纹理槽
material: |
// 最简单的测试:直接显示纹理
#if SIMPLE_TEXTURE_TEST
// 尝试读取纹理
vec4 texture_sample = texture(p3d_Texture3, texcoord);
float texture_value = texture_sample.r; // 读取红色通道
// 直接将纹理值显示为颜色
m.basecolor = vec3(texture_value); // 灰度显示
m.roughness = 0.5; // 固定粗糙度
m.metallic = 0.0; // 非金属
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// 正常材质
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# 最简单的纹理测试效果
# 直接将纹理显示为颜色,验证纹理是否被正确读取
fragment:
defines: |
#define SIMPLE_TEXTURE_TEST 1
inout: |
uniform sampler2D p3d_Texture3; // 粗糙度纹理槽
material: |
// 最简单的测试:直接显示纹理
#if SIMPLE_TEXTURE_TEST
// 尝试读取纹理
vec4 texture_sample = texture(p3d_Texture3, texcoord);
float texture_value = texture_sample.r; // 读取红色通道
// 直接将纹理值显示为颜色
m.basecolor = vec3(texture_value); // 灰度显示
m.roughness = 0.5; // 固定粗糙度
m.metallic = 0.0; // 非金属
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// 正常材质
m.basecolor = mInput.color;
m.roughness = mInput.roughness;
m.metallic = mInput.metallic;
m.specular_ior = mInput.specular_ior;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,26 +1,26 @@
# simple_transparent.yaml
vertex_shader: |
#version 330
uniform mat4 p3d_ModelViewProjectionMatrix;
in vec4 p3d_Vertex;
in vec2 p3d_MultiTexCoord0;
out vec2 texcoord;
void main() {
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
texcoord = p3d_MultiTexCoord0;
}
fragment_shader: |
#version 330
uniform sampler2D p3d_Texture0;
uniform float material_opacity = 1.0;
in vec2 texcoord;
out vec4 o_color;
void main() {
vec4 c = texture(p3d_Texture0, texcoord);
o_color = vec4(c.rgb, c.a * material_opacity);
}
render_states:
TransparencyAttrib: M_alpha
# simple_transparent.yaml
vertex_shader: |
#version 330
uniform mat4 p3d_ModelViewProjectionMatrix;
in vec4 p3d_Vertex;
in vec2 p3d_MultiTexCoord0;
out vec2 texcoord;
void main() {
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
texcoord = p3d_MultiTexCoord0;
}
fragment_shader: |
#version 330
uniform sampler2D p3d_Texture0;
uniform float material_opacity = 1.0;
in vec2 texcoord;
out vec4 o_color;
void main() {
vec4 c = texture(p3d_Texture0, texcoord);
o_color = vec4(c.rgb, c.a * material_opacity);
}
render_states:
TransparencyAttrib: M_alpha
DepthWriteAttrib: 0

View File

@ -0,0 +1,21 @@
# SSBO Instancing Effect
vertex:
includes: |
struct Transform {
mat4 model_mat;
};
#extension GL_ARB_shader_storage_buffer_object : enable
layout(std430, binding = 10) buffer ShaderBuffer {
Transform transforms[];
};
transform: |
// Overwrite position and normal using SSBO data
mat4 model_matrix = transforms[gl_InstanceID].model_mat;
vOutput.position = (model_matrix * p3d_Vertex).xyz;
// Transform normal (approximation assuming uniform scale for performance, otherwise use inverse transpose)
mat3 normal_matrix = mat3(model_matrix);
vOutput.normal = normalize(normal_matrix * p3d_Normal);

View File

@ -1,34 +1,34 @@
# Test metallic texture debug effect
# This effect shows the metallic texture directly as color to verify it's working
fragment:
defines: |
#define TEST_METALLIC_DEBUG 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Debug: Show metallic texture directly as color
#if TEST_METALLIC_DEBUG
// Sample metallic texture
float metallic_value = texture(p3d_Texture5, texcoord).x;
// Show metallic as blue-to-yellow gradient for debugging
vec3 debug_color = mix(vec3(0.2, 0.2, 1.0), vec3(1.0, 1.0, 0.2), metallic_value);
// Apply debug visualization
m.basecolor = debug_color; // Show texture as blue-yellow gradient
m.roughness = 0.5; // Fixed roughness for consistent lighting
m.metallic = 0.0; // Non-metallic for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Normal material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Test metallic texture debug effect
# This effect shows the metallic texture directly as color to verify it's working
fragment:
defines: |
#define TEST_METALLIC_DEBUG 1
inout: |
uniform sampler2D p3d_Texture5; // Metallic texture
material: |
// Debug: Show metallic texture directly as color
#if TEST_METALLIC_DEBUG
// Sample metallic texture
float metallic_value = texture(p3d_Texture5, texcoord).x;
// Show metallic as blue-to-yellow gradient for debugging
vec3 debug_color = mix(vec3(0.2, 0.2, 1.0), vec3(1.0, 1.0, 0.2), metallic_value);
// Apply debug visualization
m.basecolor = debug_color; // Show texture as blue-yellow gradient
m.roughness = 0.5; // Fixed roughness for consistent lighting
m.metallic = 0.0; // Non-metallic for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Normal material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
m.shading_model_param0 = mInput.arbitrary0;
#endif

View File

@ -1,34 +1,34 @@
# Test roughness texture debug effect
# This effect shows the roughness texture directly as color to verify it's working
fragment:
defines: |
#define TEST_ROUGHNESS_DEBUG 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture
material: |
// Debug: Show roughness texture directly as color
#if TEST_ROUGHNESS_DEBUG
// Sample roughness texture
float roughness_value = texture(p3d_Texture3, texcoord).x;
// Show roughness as grayscale color for debugging
vec3 debug_color = vec3(roughness_value);
// Apply debug visualization
m.basecolor = debug_color; // Show texture as grayscale
m.roughness = 0.5; // Fixed roughness for consistent lighting
m.metallic = 0.0; // Non-metallic for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Normal material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
m.shading_model_param0 = mInput.arbitrary0;
#endif
# Test roughness texture debug effect
# This effect shows the roughness texture directly as color to verify it's working
fragment:
defines: |
#define TEST_ROUGHNESS_DEBUG 1
inout: |
uniform sampler2D p3d_Texture3; // Roughness texture
material: |
// Debug: Show roughness texture directly as color
#if TEST_ROUGHNESS_DEBUG
// Sample roughness texture
float roughness_value = texture(p3d_Texture3, texcoord).x;
// Show roughness as grayscale color for debugging
vec3 debug_color = vec3(roughness_value);
// Apply debug visualization
m.basecolor = debug_color; // Show texture as grayscale
m.roughness = 0.5; // Fixed roughness for consistent lighting
m.metallic = 0.0; // Non-metallic for clear visualization
m.specular_ior = 1.5;
m.shading_model_param0 = 0.0;
#else
// Normal material processing
m.basecolor = mInput.color * sampled_diffuse.xyz;
m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
m.roughness = mInput.roughness * sampled_roughness;
m.metallic = mInput.metallic;
m.shading_model_param0 = mInput.arbitrary0;
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -30,7 +30,7 @@ import os
import sys
import subprocess
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from panda3d.core import Vec4, Vec3, Vec2, RenderState, TransformState
from panda3d.core import TexturePool, SceneGraphAnalyzer
@ -75,7 +75,6 @@ class Debugger(RPObject):
Globals.base.doMethodLater(0.1, self.update_stats, "RPDebugger_updateStats")
@property
def advanced_info(self):
return self.pipeline.settings["pipeline.advanced_debugging_info"]
@ -225,11 +224,6 @@ class Debugger(RPObject):
self.overlay_node.show()
self.error_msg_handler.show()
def hide_gui(self):
self.fullscreen_node.hide()
self.overlay_node.hide()
self.error_msg_handler.hide()
def toggle_keybindings_visible(self):
""" Shows / Hides the FPS graph """
if not self.keybinding_instructions.is_hidden():

View File

@ -25,7 +25,7 @@ THE SOFTWARE.
"""
from __future__ import division
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rpcore.gui.sprite import Sprite
from rpcore.rpobject import RPObject

View File

@ -90,10 +90,6 @@ class LightManager(RPObject):
def remove_light(self, light):
""" Removes a light """
print(f'333333333333333333333333333333,{light.casts_shadows}')
# from RenderPipelineFile.rpcore.pynative.internal_light_manager import InternalLightManager
# inter = InternalLightManager()
# inter.remove_light(light)
self.internal_mgr.remove_light(light)
self.pta_max_light_index[0] = self.internal_mgr.max_light_index

View File

@ -80,7 +80,6 @@ if NATIVE_CXX_LOADED:
RPObject.global_debug("CORE", "Using native core module")
from rpcore.native import native_ as _native_module # pylint: disable=wrong-import-position
else:
print(f'343434343434343434343434343')
from rpcore import pynative as _native_module # pylint: disable=wrong-import-position
RPObject.global_debug("CORE", "Using simulated python-wrapper module")

View File

@ -161,12 +161,7 @@ public:
// Update maximum index
if (slot == _max_index) {
while (_max_index >= 0 && !_data[_max_index--]);
// 正确的修复代码
// while (_max_index >= 0 && _data[_max_index] == NULL) {
// _max_index--;
// }
}
while (_max_index >= 0 && !_data[_max_index--]);
}
}

View File

@ -24,14 +24,11 @@ THE SOFTWARE.
"""
from __future__ import division, print_function
from math import exp, log
from panda3d.core import PTAFloat, PTALVecBase3f
from rpcore.rpobject import RPObject
from rpcore.util.smooth_connected_curve import SmoothConnectedCurve
from rpcore.pluginbase.setting_types import make_setting_from_factory

View File

@ -116,70 +116,30 @@ class InternalLightManager(object):
source.set_slot(slot)
def remove_light(self, light):
print(f'44444444444444444444444444')
print("\n" + "=" * 50)
print(f"DEBUG: Entering remove_light for light object: {light.casts_shadows}")
if light:
print(f" - Light's Slot: {light.get_slot() if light.has_slot() else 'No Slot'}")
print(f" - Does it cast shadows? light.get_casts_shadows() -> {light.get_casts_shadows()}")
else:
print(" - Light object is None!")
print("\n --- State of Light System BEFORE removal ---")
if hasattr(self, '_lights') and hasattr(self._lights, '_data'):
# 打印出当前所有灯光对象,看看有没有异常
print(f" - Light Data Array (_data):")
for i, l_obj in enumerate(self._lights._data):
print(f" [{i}]: {l_obj}")
print(f"\n - Max Index (_max_index): {self._lights._max_index}")
print(f" - Num Entries (_num_entries): {self._lights._num_entries}")
print("=" * 50 + "\n")
assert light is not None
if not light.has_slot():
print("ERROR: Could not detach light, light was not attached!")
return
# 保存必要信息,避免过早清理
light_slot = light.get_slot()
has_shadows = light.get_casts_shadows()
# 处理shadow sources如果有的话
if has_shadows:
num_sources = light.get_num_shadow_sources()
if num_sources > 0:
# 关键修复先保存第一个source的slot再清理
first_source = light.get_shadow_source(0)
first_source_slot = first_source.get_slot() # 保存slot值
# --- 在这里加上打印语句 ---
print(f"DEBUG: Removing shadow sources. Start Slot: {first_source_slot}, Count: {num_sources}")
# 先发送GPU移除命令在清理之前
cmd_remove = GPUCommand(GPUCommand.CMD_remove_sources)
cmd_remove.push_int(first_source_slot) # 使用保存的slot值
cmd_remove.push_int(num_sources)
self._cmd_list.add_command(cmd_remove)
# 然后清理所有shadow sources
for i in range(num_sources):
source = light.get_shadow_source(i)
if source.has_slot():
self._shadow_sources.free_slot(source.get_slot())
if source.has_region():
self._shadow_manager.get_atlas().free_region(source.get_region())
source.clear_region()
# 清理light的shadow sources
light.clear_shadow_sources()
# 发送GPU移除light命令
self._lights.free_slot(light.get_slot())
self.gpu_remove_light(light)
# 最后释放light slot和清理light信息
self._lights.free_slot(light_slot)
light.remove_slot()
if light.get_casts_shadows():
for i in range(light.get_num_shadow_sources()):
source = light.get_shadow_source(i)
if source.has_slot():
self._shadow_sources.free_slot(source.get_slot())
if source.has_region():
self._shadow_manager.get_atlas().free_region(source.get_region())
source.clear_region()
self.gpu_remove_consecutive_sources(
light.get_shadow_source(0), light.get_num_shadow_sources())
light.clear_shadow_sources()
def gpu_remove_consecutive_sources(self, first_source, num_sources):
cmd_remove = GPUCommand(GPUCommand.CMD_remove_sources)
cmd_remove.push_int(first_source.get_slot())

View File

@ -38,7 +38,7 @@ from direct.showbase.ShowBase import ShowBase
from direct.stdpy.file import isfile
from rplibs.yaml import load_yaml_file_flat
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rpcore.globals import Globals
from rpcore.effect import Effect
@ -86,8 +86,7 @@ class RenderPipeline(RPObject):
self._applied_effects = []
self._pre_showbase_initialized = False
self._first_frame = None
#self.set_loading_screen_image("/$$rp/data/gui/loading_screen_bg.txo")
self.set_loading_screen_image("/$$rp/data/gui/Default_Rough.png")
self.set_loading_screen_image("/$$rp/data/gui/loading_screen_bg.txo")
def load_settings(self, path):
""" Loads the pipeline configuration from a given filename. Usually
@ -208,7 +207,6 @@ class RenderPipeline(RPObject):
def remove_light(self, light):
""" Removes a previously attached light, check out the LightManager
remove_light documentation for further information. """
print(f'222222222222222222222222222,{light.casts_shadows}')
self.light_mgr.remove_light(light)
def load_ies_profile(self, filename):
@ -351,11 +349,7 @@ class RenderPipeline(RPObject):
continue
material = state.get_attrib(MaterialAttrib).get_material()
if material.emission is not None:
shading_model = material.emission.x
else:
shading_model = 0.0
shading_model = material.emission.x
# SHADING_MODEL_TRANSPARENT
if shading_model == 3:

View File

@ -31,7 +31,7 @@ from panda3d.core import Vec4, TransparencyAttrib, ColorWriteAttrib, SamplerStat
from panda3d.core import WindowProperties, FrameBufferProperties, GraphicsPipe
from panda3d.core import LVecBase2i
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rplibs.six import iterkeys, itervalues
from rpcore.globals import Globals

View File

@ -71,8 +71,8 @@ class DisplayShaderBuilder(object): # pylint: disable=too-few-public-methods
# Build actual shader
built = """
#version 400
#pragma include "render_pipeline_base.inc.glsl"
#extension GL_ARB_shading_language_420pack : enable
#pragma include "render_pipeline_base.inc.glsl"
in vec2 texcoord;
out vec3 result;
uniform int mipmap;

View File

@ -36,7 +36,7 @@ from panda3d.core import PTAFloat, Filename, SamplerState, VirtualFileSystem
from panda3d.core import get_model_path
from direct.stdpy.file import open, join, isfile
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rpcore.native import IESDataset
from rpcore.image import Image

View File

@ -60,7 +60,7 @@ class MovementController(object):
self.keyboard_hpr_speed = 0.4
self.use_hpr = False
self.smoothness = 6.0
self.bobbing_amount = 0.0
self.bobbing_amount = 1.5
self.bobbing_speed = 0.5
def set_initial_position(self, pos, target):
@ -138,8 +138,8 @@ class MovementController(object):
self.showbase.accept("j", self.print_position)
# mouse
self.showbase.accept("mouse3", self.set_mouse_enabled, [True])
self.showbase.accept("mouse3-up", self.set_mouse_enabled, [False])
self.showbase.accept("mouse1", self.set_mouse_enabled, [True])
self.showbase.accept("mouse1-up", self.set_mouse_enabled, [False])
# arrow mouse navigation
self.showbase.accept("arrow_up", self.set_hpr_movement, [1, 1])

View File

@ -127,20 +127,9 @@ class NetworkCommunication(RPObject):
be an update of a plugin setting """
if cmd.startswith("setval "):
parts = cmd.split()
if len(parts) < 3:
self.warn("Invalid setval command format. Expected: setval plugin.setting value")
return
setting_parts = parts[1].split(".")
if len(setting_parts) < 2:
self.warn("Invalid setting format. Expected: plugin.setting")
return
try:
self._pipeline.plugin_mgr.on_setting_changed(
setting_parts[0], setting_parts[1], parts[2])
except Exception as e:
self.warn("Error handling setting change:", str(e))
self._pipeline.plugin_mgr.on_setting_changed(
setting_parts[0], setting_parts[1], parts[2])
else:
self.warn("Recieved unkown plugin command:", cmd)

View File

@ -24,7 +24,7 @@ THE SOFTWARE.
"""
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from panda3d.core import Vec3, CurveFitter

View File

@ -1,6 +1,4 @@
"""Utilities for writing code that runs on Python 2 and 3"""
# Copyright (c) 2010-2015 Benjamin Peterson
# Copyright (c) 2010-2020 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -20,6 +18,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Utilities for writing code that runs on Python 2 and 3"""
from __future__ import absolute_import
import functools
@ -29,7 +29,7 @@ import sys
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
__version__ = "1.10.0"
__version__ = "1.16.0"
# Useful for very coarse version differentiation.
@ -71,6 +71,11 @@ else:
MAXSIZE = int((1 << 63) - 1)
del X
if PY34:
from importlib.util import spec_from_loader
else:
spec_from_loader = None
def _add_doc(func, doc):
"""Add documentation to a function."""
@ -186,6 +191,11 @@ class _SixMetaPathImporter(object):
return self
return None
def find_spec(self, fullname, path, target=None):
if fullname in self.known_modules:
return spec_from_loader(fullname, self)
return None
def __get_module(self, fullname):
try:
return self.known_modules[fullname]
@ -223,6 +233,12 @@ class _SixMetaPathImporter(object):
return None
get_source = get_code # same as get_code
def create_module(self, spec):
return self.load_module(spec.name)
def exec_module(self, module):
pass
_importer = _SixMetaPathImporter(__name__)
@ -241,6 +257,7 @@ _moved_attributes = [
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
MovedAttribute("getoutput", "commands", "subprocess"),
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
MovedAttribute("reduce", "__builtin__", "functools"),
@ -254,18 +271,21 @@ _moved_attributes = [
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
MovedModule("copyreg", "copy_reg"),
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
MovedModule("http_cookies", "Cookie", "http.cookies"),
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
MovedModule("html_parser", "HTMLParser", "html.parser"),
MovedModule("http_client", "httplib", "http.client"),
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
@ -337,10 +357,12 @@ _urllib_parse_moved_attributes = [
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
MovedAttribute("unquote", "urllib", "urllib.parse"),
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"),
MovedAttribute("urlencode", "urllib", "urllib.parse"),
MovedAttribute("splitquery", "urllib", "urllib.parse"),
MovedAttribute("splittag", "urllib", "urllib.parse"),
MovedAttribute("splituser", "urllib", "urllib.parse"),
MovedAttribute("splitvalue", "urllib", "urllib.parse"),
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
@ -416,6 +438,8 @@ _urllib_request_moved_attributes = [
MovedAttribute("URLopener", "urllib", "urllib.request"),
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
setattr(Module_six_moves_urllib_request, attr.name, attr)
@ -631,13 +655,16 @@ if PY3:
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
del io
_assertCountEqual = "assertCountEqual"
if sys.version_info[1] <= 1:
_assertRaisesRegex = "assertRaisesRegexp"
_assertRegex = "assertRegexpMatches"
_assertNotRegex = "assertNotRegexpMatches"
else:
_assertRaisesRegex = "assertRaisesRegex"
_assertRegex = "assertRegex"
_assertNotRegex = "assertNotRegex"
else:
def b(s):
return s
@ -659,6 +686,7 @@ else:
_assertCountEqual = "assertItemsEqual"
_assertRaisesRegex = "assertRaisesRegexp"
_assertRegex = "assertRegexpMatches"
_assertNotRegex = "assertNotRegexpMatches"
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
@ -675,15 +703,23 @@ def assertRegex(self, *args, **kwargs):
return getattr(self, _assertRegex)(*args, **kwargs)
def assertNotRegex(self, *args, **kwargs):
return getattr(self, _assertNotRegex)(*args, **kwargs)
if PY3:
exec_ = getattr(moves.builtins, "exec")
def reraise(tp, value, tb=None):
if value is None:
value = tp()
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
finally:
value = None
tb = None
else:
def exec_(_code_, _globs_=None, _locs_=None):
@ -699,19 +735,19 @@ else:
exec("""exec _code_ in _globs_, _locs_""")
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
try:
raise tp, value, tb
finally:
tb = None
""")
if sys.version_info[:2] == (3, 2):
if sys.version_info[:2] > (3,):
exec_("""def raise_from(value, from_value):
if from_value is None:
raise value
raise value from from_value
""")
elif sys.version_info[:2] > (3, 2):
exec_("""def raise_from(value, from_value):
raise value from from_value
try:
raise value from from_value
finally:
value = None
""")
else:
def raise_from(value, from_value):
@ -786,13 +822,33 @@ if sys.version_info[:2] < (3, 3):
_add_doc(reraise, """Reraise an exception.""")
if sys.version_info[0:2] < (3, 4):
# This does exactly the same what the :func:`py3:functools.update_wrapper`
# function does on Python versions after 3.2. It sets the ``__wrapped__``
# attribute on ``wrapper`` object and it doesn't raise an error if any of
# the attributes mentioned in ``assigned`` and ``updated`` are missing on
# ``wrapped`` object.
def _update_wrapper(wrapper, wrapped,
assigned=functools.WRAPPER_ASSIGNMENTS,
updated=functools.WRAPPER_UPDATES):
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
continue
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
wrapper.__wrapped__ = wrapped
return wrapper
_update_wrapper.__doc__ = functools.update_wrapper.__doc__
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
updated=functools.WRAPPER_UPDATES):
def wrapper(f):
f = functools.wraps(wrapped, assigned, updated)(f)
f.__wrapped__ = wrapped
return f
return wrapper
return functools.partial(_update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
wraps.__doc__ = functools.wraps.__doc__
else:
wraps = functools.wraps
@ -802,10 +858,22 @@ def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(meta):
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
if sys.version_info[:2] >= (3, 7):
# This version introduced PEP 560 that requires a bit
# of extra care (we mimic what is done by __build_class__).
resolved_bases = types.resolve_bases(bases)
if resolved_bases is not bases:
d['__orig_bases__'] = bases
else:
resolved_bases = bases
return meta(name, resolved_bases, d)
@classmethod
def __prepare__(cls, name, this_bases):
return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
@ -821,13 +889,75 @@ def add_metaclass(metaclass):
orig_vars.pop(slots_var)
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
if hasattr(cls, '__qualname__'):
orig_vars['__qualname__'] = cls.__qualname__
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
def ensure_binary(s, encoding='utf-8', errors='strict'):
"""Coerce **s** to six.binary_type.
For Python 2:
- `unicode` -> encoded to `str`
- `str` -> `str`
For Python 3:
- `str` -> encoded to `bytes`
- `bytes` -> `bytes`
"""
if isinstance(s, binary_type):
return s
if isinstance(s, text_type):
return s.encode(encoding, errors)
raise TypeError("not expecting type '%s'" % type(s))
def ensure_str(s, encoding='utf-8', errors='strict'):
"""Coerce *s* to `str`.
For Python 2:
- `unicode` -> encoded to `str`
- `str` -> `str`
For Python 3:
- `str` -> `str`
- `bytes` -> decoded to `str`
"""
# Optimization: Fast return for the common case.
if type(s) is str:
return s
if PY2 and isinstance(s, text_type):
return s.encode(encoding, errors)
elif PY3 and isinstance(s, binary_type):
return s.decode(encoding, errors)
elif not isinstance(s, (text_type, binary_type)):
raise TypeError("not expecting type '%s'" % type(s))
return s
def ensure_text(s, encoding='utf-8', errors='strict'):
"""Coerce *s* to six.text_type.
For Python 2:
- `unicode` -> `unicode`
- `str` -> `unicode`
For Python 3:
- `str` -> `str`
- `bytes` -> decoded to `str`
"""
if isinstance(s, binary_type):
return s.decode(encoding, errors)
elif isinstance(s, text_type):
return s
else:
raise TypeError("not expecting type '%s'" % type(s))
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
A class decorator that defines __unicode__ and __str__ methods under Python 2.
Under Python 3 it does nothing.
To support Python 2 and 3 with a single code base, define a __str__ method

View File

@ -24,7 +24,7 @@ THE SOFTWARE.
"""
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from panda3d.core import SamplerState, Vec4

View File

@ -1,3 +1,29 @@
"""
RenderPipeline
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from rpcore.render_stage import RenderStage

View File

@ -1,3 +1,29 @@
"""
RenderPipeline
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from rpcore.pluginbase.base_plugin import BasePlugin
from .dof_stage import DoFStage

View File

@ -25,7 +25,7 @@ THE SOFTWARE.
"""
from __future__ import division
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rplibs.six import itervalues
from panda3d.core import Camera, PerspectiveLens, Vec4, Vec3, PTAInt

View File

@ -25,7 +25,7 @@ THE SOFTWARE.
"""
from __future__ import print_function
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from panda3d.core import PTAVecBase3f
from rpcore.globals import Globals

View File

@ -24,7 +24,7 @@ THE SOFTWARE.
"""
from __future__ import division
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from panda3d.core import SamplerState

View File

@ -26,7 +26,7 @@ THE SOFTWARE.
import math
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rplibs.six import iteritems, itervalues
from direct.stdpy.file import listdir, isfile, join

View File

@ -1,5 +1,7 @@
#pragma once
#extension GL_ARB_shading_language_420pack : enable
// This file includes defines and functions used for the scattering
@ -7,8 +9,6 @@
#pragma include "render_pipeline_base.inc.glsl"
#extension GL_ARB_shading_language_420pack : enable
// These can be overridden depending on if the shader is a compute shader
// or a regular fragment shader

View File

@ -26,7 +26,7 @@ THE SOFTWARE.
from panda3d.core import LVecBase2i
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
from rpcore.render_stage import RenderStage

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

63
RenderPipelineFile/samples/.gitignore vendored Normal file
View File

@ -0,0 +1,63 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
*.blend1
03-Forest
*.blend1
*.blend2

View File

@ -0,0 +1,14 @@
## Render Pipeline Samples
The samples are not included in this repository to keep the size small.
#### Automatic Download (recommended)
You can run `python download_samples.py` to automatically download the samples.
#### Manual Download
If you want to manually download the samples (for whatever reason), you can
find them here:
<a href="https://github.com/tobspr/RenderPipeline-Samples
">https://github.com/tobspr/RenderPipeline-Samples</a>
After downloading, place the downloaded contents in this folder to run the samples.

View File

@ -0,0 +1,44 @@
"""
RenderPipeline
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
# Script to download the Render Pipeline samples
import os
import sys
sys.path.insert(0, "../")
sys.path.insert(0, "../rpcore/util")
from submodule_downloader import download_submodule # noqa
if __name__ == "__main__":
# Make sure we are in the right directory
main_dir = os.path.dirname(os.path.realpath(__file__))
os.chdir(main_dir)
# Now extract the samples
download_submodule("tobspr", "RenderPipeline-Samples", ".", ["README.md", "LICENSE"])

View File

@ -47,7 +47,7 @@ CURRENT_STEP = 0
os.chdir(SETUP_DIR)
sys.path.insert(0, ".")
from six.moves import input # pylint: disable=import-error
from rplibs.six.moves import input # pylint: disable=import-error
# Load and init colorama, used to color the output
from rplibs.colorama import init as init_colorama

View File

@ -0,0 +1,2 @@
n
n

View File

@ -25,15 +25,11 @@ THE SOFTWARE.
"""
from __future__ import print_function
# from PyQt5 import Qt
# from PyQt5.QtGui import QPainter, QColor, QPen
# from PyQt5.QtWidgets import QWidget
from six.moves import range # pylint: disable=import-error
from rplibs.six.moves import range # pylint: disable=import-error
import math
from RenderPipelineFile.rplibs.pyqt_imports import * # noqa
from rplibs.pyqt_imports import * # noqa
class CurveWidget(QWidget):
@ -216,13 +212,13 @@ class CurveWidget(QWidget):
painter.setPen(QColor(200, 200, 200))
for i in range(num_vert_lines + 1):
line_pos = i * line_spacing_x + self._legend_border - 1
painter.drawLine(int(line_pos), self._bar_h, int(line_pos), canvas_height + self._bar_h)
painter.drawLine(line_pos, self._bar_h, line_pos, canvas_height + self._bar_h)
# Draw horizontal lines
painter.setPen(QColor(200, 200, 200))
for i in range(num_horiz_lines):
line_pos = canvas_height - i * line_spacing_y + self._bar_h
painter.drawLine(self._legend_border, int(line_pos), self.width(), int(line_pos))
painter.drawLine(self._legend_border, line_pos, self.width(), line_pos)
# Draw vetical legend labels
painter.setPen(QColor(120, 120, 120))
@ -230,7 +226,7 @@ class CurveWidget(QWidget):
line_pos = canvas_height - i * line_spacing_y + self._bar_h
# painter.drawText(6, line_pos + 3, str(round(float(i) / (num_horiz_lines-1), 2)))
painter.drawText(
6, int(line_pos + 3), self._unit_processor(float(i) / (num_horiz_lines - 1)))
6, line_pos + 3, self._unit_processor(float(i) / (num_horiz_lines - 1)))
# Draw horizontal legend labels
for i in range(num_vert_lines + 1):
@ -241,7 +237,7 @@ class CurveWidget(QWidget):
elif i == num_vert_lines:
offpos_x = -27
time_string = str(int(float(i) / num_vert_lines * 24)).zfill(2) + ":00"
painter.drawText(int(line_pos + offpos_x), canvas_height + self._bar_h + 18, time_string)
painter.drawText(line_pos + offpos_x, canvas_height + self._bar_h + 18, time_string)
# Draw curve
for index, curve in enumerate(self._curves):
@ -255,7 +251,7 @@ class CurveWidget(QWidget):
last_value = curve_height
painter.drawLine(
int(self._legend_border + i - 1), int(last_value), int(self._legend_border + i), int(curve_height))
self._legend_border + i - 1, last_value, self._legend_border + i, curve_height)
last_value = curve_height
# Draw the CV points of the curve
@ -271,7 +267,7 @@ class CurveWidget(QWidget):
else:
painter.setPen(QColor(100, 100, 100))
painter.drawRect(
int(offs_x - self._cv_point_size), int(offs_y - self._cv_point_size),
offs_x - self._cv_point_size, offs_y - self._cv_point_size,
2 * self._cv_point_size, 2 * self._cv_point_size)
# Draw bar background
@ -306,7 +302,7 @@ class CurveWidget(QWidget):
g = max(0, min(255, int(bar_curve[1].get_value(relv) * 255.0)))
b = max(0, min(255, int(bar_curve[2].get_value(relv) * 255.0)))
painter.setPen(QColor(r, g, b))
painter.drawLine(int(xpos), bar_top_pos, int(xpos), bar_top_pos + 2 * bar_half_height)
painter.drawLine(xpos, bar_top_pos, xpos, bar_top_pos + 2 * bar_half_height)
# Draw selected time
if self._drag_point:
@ -316,14 +312,14 @@ class CurveWidget(QWidget):
canvas_width + 10, self._drag_time * canvas_width + self._legend_border - 19))
offs_y = self.height() - self._legend_border
minutes = int(self._drag_time * 24 * 60)
hours = int(minutes / 60)
hours = minutes / 60
minutes = minutes % 60
painter.drawRect(int(offs_x), self.height() - self._legend_border + 5, 40, 20)
painter.drawText(int(offs_x + 7), offs_y + 20, "{:02}:{:02}".format(int(hours), int(minutes)))
painter.drawRect(offs_x, self.height() - self._legend_border + 5, 40, 20)
painter.drawText(offs_x + 7, offs_y + 20, "{:02}:{:02}".format(hours, minutes))
painter.setPen(QColor(150, 150, 150))
painter.drawLine(
int(offs_x) + 19, bar_top_pos + 15, int(offs_x + 19), self.height() - self._legend_border + 5)
offs_x + 19, bar_top_pos + 15, offs_x + 19, self.height() - self._legend_border + 5)
# Display current time
pen = QPen()
@ -332,7 +328,7 @@ class CurveWidget(QWidget):
painter.setPen(pen)
xoffs = self._legend_border + self._current_time * (canvas_width - 1)
painter.drawLine(int(xoffs), self._bar_h, int(xoffs), self._bar_h + canvas_height)
painter.drawLine(xoffs, self._bar_h, xoffs, self._bar_h + canvas_height)
# Draw usage hints
painter.setPen(QColor(100, 100, 100))

View File

@ -40,8 +40,8 @@ os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__))))
# Add the render pipeline to the path
sys.path.insert(0, "../../")
from RenderPipelineFile.rplibs.six import iteritems # noqa
from RenderPipelineFile.rplibs.pyqt_imports import * # noqa
from rplibs.six import iteritems # noqa
from rplibs.pyqt_imports import * # noqa
from curve_widget import CurveWidget # noqa
@ -185,10 +185,7 @@ class DayTimeEditor(QMainWindow, Ui_MainWindow):
widget.setText(1, formatted)
if setting_handle.type == "color":
color_values = [int(v*255)for v in value]
widget.setBackground(1, QBrush(QColor(*color_values)))
# else:
# widget.setBackground(1,QBrush(QColor(*value)))
widget.setBackground(1, QBrush(QColor(*value)))
def _on_curve_edited(self):
""" Called when the curve got edited in the curve widget """

View File

@ -45,7 +45,7 @@ sys.path.insert(0, "../../")
from rplibs.six import iteritems # noqa
from rplibs.pyqt_imports import * # noqa
from RenderPipelineFile.toolkit.material_editor.ui.main_window_generated import Ui_MainWindow # noqa
from ui.main_window_generated import Ui_MainWindow # noqa
from rpcore.util.network_communication import NetworkCommunication # noqa
# Allow working with an older version of the material DB.
@ -170,9 +170,9 @@ class MaterialEditor(QMainWindow, Ui_MainWindow):
# Basecolor
values = self.basecolor_to_tuple(self.material)
self.basecolor_1.setValue(int(values[0] * 100.0))
self.basecolor_2.setValue(int(values[1] * 100.0))
self.basecolor_3.setValue(int(values[2] * 100.0))
self.basecolor_1.setValue(values[0] * 100.0)
self.basecolor_2.setValue(values[1] * 100.0)
self.basecolor_3.setValue(values[2] * 100.0)
# Shading model
self.cb_shading_model.setCurrentIndex(self.material.shading_model)
@ -184,7 +184,7 @@ class MaterialEditor(QMainWindow, Ui_MainWindow):
# Rest of sliders
for slider, lbl, start, end, prop in self.sliders:
val = getattr(self.material, prop)
slider.setValue(int((val - start) / (end - start) * 100.0))
slider.setValue((val - start) / (end - start) * 100.0)
self.in_update = False
self.update_ui()

View File

@ -471,7 +471,7 @@ font-weight: 600;</string>
</size>
</property>
<property name="styleSheet">
<string notr="true">background: rgba(60, 120, 255, 1);</string>
<string notr="true">background: rgba(60, 120, 255);</string>
</property>
<property name="text">
<string/>

View File

@ -357,4 +357,4 @@ class Ui_MainWindow(object):
self.cb_srgb.setText(_translate("MainWindow", "SRGB"))
self.cb_hsv.setText(_translate("MainWindow", "HSV"))
#from . import resources_rc
from . import resources_rc

View File

@ -49,8 +49,6 @@ from rplibs.pyqt_imports import * #noqa
# Load the generated UI Layout
from ui.main_window_generated import Ui_MainWindow # noqa
from ui.widgets import UniversalMessageDialog
from rpcore.pluginbase.manager import PluginManager # noqa
from rpcore.util.network_communication import NetworkCommunication # noqa
from rpcore.mount_manager import MountManager # noqa
@ -99,11 +97,6 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
update_thread = Thread(target=self.update_thread, args=())
update_thread.start()
# 启动通信文件监听线程
comm_thread = Thread(target=self.communication_thread, args=())
comm_thread.daemon = True # 设置为守护线 程,主程序退出时自动结束
comm_thread.start()
def closeEvent(self, event): # noqa
event.accept()
import os
@ -121,13 +114,9 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
self, "Warning", msg, QMessageBox.Yes, QMessageBox.No)
if reply == QMessageBox.Yes:
UniversalMessageDialog.show_success(
self,
"Success",
"Settings have been reset! You may have to restart the pipeline.",
show_cancel=False,
confirm_text="OK"
)
QMessageBox.information(
self, "Success",
"Settings have been reset! You may have to restart the pipeline.")
self._plugin_mgr.reset_plugin_settings(self._current_plugin)
# Save config
@ -374,14 +363,14 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
if setting.type == "float":
box.setSingleStep(abs(setting.maxval - setting.minval) / 100.0)
slider.setMinimum(int(setting.minval * 100000.0))
slider.setMaximum(int(setting.maxval * 100000.0))
slider.setValue(int(setting.value * 100000.0))
slider.setMinimum(setting.minval * 100000.0)
slider.setMaximum(setting.maxval * 100000.0)
slider.setValue(setting.value * 100000.0)
elif setting.type == "int":
box.setSingleStep(int(max(1, (setting.maxval - setting.minval) / 32)))
slider.setMinimum(int(setting.minval))
slider.setMaximum(int(setting.maxval))
slider.setValue(int(setting.value))
box.setSingleStep(max(1, (setting.maxval - setting.minval) / 32))
slider.setMinimum(setting.minval)
slider.setMaximum(setting.maxval)
slider.setValue(setting.value)
layout.addWidget(box)
layout.addWidget(slider)
@ -497,84 +486,6 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
self.lst_plugins.setCurrentRow(0)
def communication_thread(self):
"""监听来自主程序的通信文件"""
import json
import tempfile
comm_dir = os.path.join(tempfile.gettempdir(), "daytime_editor_comm")
comm_file = os.path.join(comm_dir, "sun_azimuth_command.json")
print("🔄 Day Time Editor通信监听已启动")
print(f" 监听文件: {comm_file}")
last_timestamp = 0
while True:
try:
if os.path.exists(comm_file):
with open(comm_file, 'r') as f:
command = json.load(f)
# 检查是否是新命令(避免重复执行)
if command.get('timestamp', 0) > last_timestamp:
last_timestamp = command.get('timestamp', 0)
if command.get('command') == 'set_sun_azimuth':
azimuth_value = command.get('value', 0)
print(f"📨 收到Sun Azimuth命令: {azimuth_value}°")
# 在主线程中执行UI更新
QTimer.singleShot(0, partial(self.apply_sun_azimuth, azimuth_value))
time.sleep(0.1) # 100ms检查一次
except Exception as e:
print(f"⚠️ 通信监听错误: {e}")
time.sleep(1) # 出错时等待1秒再重试
def apply_sun_azimuth(self, azimuth_degrees):
"""应用Sun Azimuth值到Day Time Editor"""
try:
print(f"🌞 正在应用Sun Azimuth: {azimuth_degrees}°")
# 查找Sun Azimuth相关的控件
# 这里需要根据实际的UI结构来实现
# 先尝试找到可能的控件
# 方法1查找包含"azimuth"的控件
for widget_name in dir(self):
widget = getattr(self, widget_name, None)
if widget and hasattr(widget, 'setValue'):
if 'azimuth' in widget_name.lower() or 'sun' in widget_name.lower():
print(f" 尝试设置控件: {widget_name}")
try:
widget.setValue(azimuth_degrees)
print(f"✅ 成功设置 {widget_name} = {azimuth_degrees}°")
return
except Exception as e:
print(f" 设置失败: {e}")
# 方法2查找表格中的Sun Azimuth设置
if hasattr(self, 'table_plugin_settings'):
table = self.table_plugin_settings
for row in range(table.rowCount()):
item = table.item(row, 0) # 第一列通常是设置名称
if item and 'azimuth' in item.text().lower():
# 找到Sun Azimuth行设置第二列的值
value_item = table.item(row, 1)
if value_item:
value_item.setText(str(azimuth_degrees))
print(f"✅ 在表格中设置Sun Azimuth = {azimuth_degrees}°")
return
print("⚠️ 未找到Sun Azimuth控件请检查UI结构")
except Exception as e:
print(f"❌ 应用Sun Azimuth失败: {e}")
import traceback
traceback.print_exc()
# Start application
app = QApplication(sys.argv)
qt_register_fonts()

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

View File

@ -29,9 +29,21 @@ if __name__ == "__main__":
# 将整个列表转换为字符串(包括方括号)
args_str = ''.join(args)
from main import run
from main import MyWorld
if args:
run(args_str)
# run(args)
# print(f"[DEBUG] 启动时传入项目路径: {args_str}")
# 创建应用实例
app = MyWorld()
# 如果传入了项目路径,尝试打开项目
if hasattr(app, 'project_manager'):
# print(f"[DEBUG] 尝试打开项目: {args_str}")
success = app.project_manager.openProject(args_str)
# print(f"[DEBUG] 项目打开结果: {success}")
else:
# print(f"[DEBUG] 项目管理器未初始化")
pass
app.run()
else:
run()
# print(f"[DEBUG] 无项目路径,正常启动")
app = MyWorld()
app.run()

View File

@ -0,0 +1,104 @@
# TransformGizmo 事件钩子使用说明
本文档说明如何在 `TransformGizmo` 初始化时注入拖拽事件回调(类似 C# 委托),以及各事件的负载字段。
## 事件常量
所有事件名集中在 `TransformGizmo.events.GizmoEvent`,避免拼写错误:
```python
from src.TransformGizmo.events import GizmoEvent
GizmoEvent.DRAG_START # "drag_start"
GizmoEvent.DRAG_MOVE # "drag_move"
GizmoEvent.DRAG_END # "drag_end"
GizmoEvent.ALL # ("drag_start", "drag_move", "drag_end")
```
## 基础用法示例
在构造 `TransformGizmo` 时传入 `event_hooks`,按 handle 类型分组(`"move"`, `"rotate"`, `"scale"` 或对应 `TransformGizmoMode` 值),每组里是事件名到回调列表的映射:
```python
from src.TransformGizmo.transform_gizmo import TransformGizmo, TransformGizmoMode
from src.TransformGizmo.events import GizmoEvent
def on_move_start(info):
print("[move] start", "axis", info["axis"], "plane", info["plane"])
def on_move_drag(info):
print("[move] pos ->", info["new_pos"])
def on_rotate_drag(info):
print("[rotate] delta_deg =", info["delta_deg"])
def on_scale_end(info):
print("[scale] final_scale =", info["final_scale"])
hooks = {
TransformGizmoMode.MOVE: {
GizmoEvent.DRAG_START: [on_move_start],
GizmoEvent.DRAG_MOVE: [on_move_drag],
},
TransformGizmoMode.ROTATE: {
GizmoEvent.DRAG_MOVE: [on_rotate_drag],
},
TransformGizmoMode.SCALE: {
GizmoEvent.DRAG_END: [on_scale_end],
},
}
# world: 你的 Panda3DWorld 实例
gizmo = TransformGizmo(world, event_hooks=hooks)
```
### 运行时追加 / 移除
初始化后也可以直接操作子 gizmo 的钩子列表:
```python
from src.TransformGizmo.events import GizmoEvent
gizmo.move_gizmo._event_hooks[GizmoEvent.DRAG_MOVE].append(on_move_drag)
# 移除同理,用 list.remove(on_move_drag)
```
## 回调负载字段
各事件都会传入一个 `dict`,常见字段如下(不存在的字段将为 `None` 或缺省):
### Move
- `axis`0/1/2X/Y/Z平面拖拽时为 `None`
- `plane`0/1/2XY/YZ/ZX轴拖拽时为 `None`
- `mouse``Point2`,拖拽开始/过程中鼠标 NDC 坐标
- `start_pos` / `new_pos` / `final_pos`:世界坐标 `Vec3`
- `target`:当前绑定的 `NodePath`
- `gizmo`:字符串 `"move"`
### Rotate
- `mode``"axis"` 或 `"trackball"`
- `axis`0/1/2X/Y/Z轨迹球时为 `None`
- `delta_deg`:本次 `drag_move` 的角度增量(度)
- `start_quat`:拖拽开始时的世界四元数
- `final_hpr`:拖拽结束时的世界 HPR`drag_end`
- `center`gizmo 中心点(世界坐标)
- `axis_world`:当前旋转轴的世界方向
- `mouse``Point2`
- `target``gizmo` 同上
### Scale
- `axis`0/1/2 对应 X/Y/Z3 表示中心均匀缩放
- `scale_factor`:本次 `drag_move` 计算出的缩放倍率
- `start_scale` / `new_scale` / `final_scale``Vec3`
- `mouse``Point2`
- `target``gizmo` 同上
## 小贴士
- 事件字典的键可以用字符串 `"move"`/`"rotate"`/`"scale"`,也可以用 `TransformGizmoMode` 的对应值,内部都会匹配。
- 每个事件支持多个回调(列表),内部对单个回调异常做了 try/except互不影响。
- 如果只想监听部分事件,留空即可,内部会自动填充为空列表。

21
TransformGizmo/events.py Normal file
View File

@ -0,0 +1,21 @@
class GizmoEvent:
"""String constants for gizmo event hook names."""
DRAG_START = "drag_start"
DRAG_MOVE = "drag_move"
DRAG_END = "drag_end"
ALL = (DRAG_START, DRAG_MOVE, DRAG_END)
class TransformGizmoMode:
"""Simple string constants for gizmo modes."""
NONE = "none"
MOVE = "move"
ROTATE = "rotate"
SCALE = "scale" # reserved for future implementation
ALL = "all" # move + rotate together (matches existing UI semantics)
__all__ = ["GizmoEvent", "TransformGizmoMode"]

Some files were not shown because too many files have changed in this diff Show More