Compare commits
10 Commits
fd18d22c20
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e876518844 | ||
|
|
86544c4d9b | ||
|
|
04c0eb0b9a | ||
|
|
ba7b249f48 | ||
|
|
a09c20bba6 | ||
|
|
85f2e82e12 | ||
|
|
ed37d800c2 | ||
|
|
565bb02a28 | ||
|
|
5478efef6c | ||
|
|
529384a8e6 |
87
README.md
87
README.md
@@ -1,34 +1,38 @@
|
||||
# 3D光学系统建模工具
|
||||
# 3D 光学系统建模工具
|
||||
|
||||
这个项目可以将JSON格式的光学系统数据转换为3D模型,使用Blender生成高质量的可视化结果。
|
||||
这个项目可以将 JSON 格式的光学系统数据转换为 3D 模型,使用 Blender 生成高质量的可视化结果。
|
||||
|
||||
## 🚀 功能特色
|
||||
|
||||
- **精确几何建模**: 支持平面、抛物面、双曲面等光学面型
|
||||
- **智能材质系统**: 自动应用金属、透明、发光材质
|
||||
- **多格式输出**: 生成OBJ、GLB、Blender文件和渲染图像
|
||||
- **多格式输出**: 生成 OBJ、GLB、Blender 文件和渲染图像
|
||||
- **自动场景设置**: 包含相机、灯光和渲染配置
|
||||
- **错误处理**: 完善的异常处理和日志输出
|
||||
|
||||
## 📋 系统要求
|
||||
|
||||
- **Blender 3.6+** (推荐 4.0+)
|
||||
- **Python 3.7+**
|
||||
- **Python 3.11+**
|
||||
- **操作系统**: Windows, macOS, Linux
|
||||
|
||||
## 🛠️ 安装
|
||||
|
||||
### 1. 安装Blender
|
||||
### 1. 安装 Blender
|
||||
|
||||
从官网下载并安装: https://www.blender.org/download/
|
||||
|
||||
### 2. 验证安装
|
||||
|
||||
```bash
|
||||
# 确保可以从命令行访问Blender
|
||||
blender --version
|
||||
```
|
||||
|
||||
### 3. 准备数据文件
|
||||
确保您的JSON数据文件格式正确,包含以下结构:
|
||||
|
||||
确保您的 JSON 数据文件格式正确,包含以下结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"p": [0.0, 0.0, 0.0],
|
||||
@@ -51,46 +55,58 @@ blender --version
|
||||
|
||||
## 🎯 使用方法
|
||||
|
||||
### 方法1: 使用运行脚本(推荐)
|
||||
---------------------阅读到此请直接阅读 use.md 以下暂时废弃----------------------------------
|
||||
|
||||
### 方法 1: 使用运行脚本(推荐)
|
||||
|
||||
```bash
|
||||
python run_blender.py -i jsonfile.json
|
||||
```
|
||||
|
||||
### 方法2: 直接运行Blender脚本
|
||||
### 方法 2: 直接运行 Blender 脚本
|
||||
|
||||
```bash
|
||||
blender --background --python toModel.py
|
||||
```
|
||||
|
||||
### 方法3: 在Blender GUI中运行
|
||||
1. 打开Blender
|
||||
2. 切换到Scripting工作区
|
||||
### 方法 3: 在 Blender GUI 中运行
|
||||
|
||||
1. 打开 Blender
|
||||
2. 切换到 Scripting 工作区
|
||||
3. 打开 `toModel.py` 文件
|
||||
4. 点击运行按钮
|
||||
|
||||
### 综合
|
||||
|
||||
✅ 融合光学系统脚本执行成功!
|
||||
|
||||
## 📁 输出文件
|
||||
|
||||
运行成功后,将生成以下文件:
|
||||
|
||||
| 文件名 | 格式 | 用途 |
|
||||
|--------|------|------|
|
||||
| `optical_system.obj` | OBJ | 通用3D模型格式,可在大多数3D软件中打开 |
|
||||
| `optical_system.glb` | GLB | Web友好格式,适合在线展示 |
|
||||
| `optical_system.blend` | Blender | 完整的Blender工程文件,包含所有材质和设置 |
|
||||
| `optical_system_render.png` | PNG | 高质量渲染图像 |
|
||||
| 文件名 | 格式 | 用途 |
|
||||
| --------------------------- | ------- | ------------------------------------------- |
|
||||
| `optical_system.obj` | OBJ | 通用 3D 模型格式,可在大多数 3D 软件中打开 |
|
||||
| `optical_system.glb` | GLB | Web 友好格式,适合在线展示 |
|
||||
| `optical_system.blend` | Blender | 完整的 Blender 工程文件,包含所有材质和设置 |
|
||||
| `optical_system_render.png` | PNG | 高质量渲染图像 |
|
||||
|
||||
## ⚙️ 配置选项
|
||||
|
||||
### 几何体类型支持
|
||||
|
||||
- **plane**: 平面镜/透镜
|
||||
- **parabola**: 抛物面镜,使用 `face_f` 参数控制焦距
|
||||
- **hyperbola**: 双曲面镜,使用 `face_f` 和 `face_g` 参数
|
||||
|
||||
### 材质类型
|
||||
|
||||
- **metal**: 金属反射材质(淡蓝色)
|
||||
- **nothing**: 透明材质(10%不透明度)
|
||||
- **其他**: 发光材质(橙色光)
|
||||
|
||||
### 渲染设置
|
||||
|
||||
- 分辨率: 1920x1080
|
||||
- 引擎: Cycles(支持高质量材质)
|
||||
- 格式: PNG
|
||||
@@ -98,7 +114,9 @@ blender --background --python toModel.py
|
||||
## 🔧 自定义
|
||||
|
||||
### 修改材质
|
||||
|
||||
编辑 `toModel.py` 中的材质创建函数:
|
||||
|
||||
```python
|
||||
def create_metal_material():
|
||||
# 修改金属材质属性
|
||||
@@ -108,12 +126,15 @@ def create_metal_material():
|
||||
```
|
||||
|
||||
### 调整几何体精度
|
||||
|
||||
修改分辨率参数:
|
||||
|
||||
```python
|
||||
mesh = create_parabolic_surface(face_f, size=2.0, resolution=64) # 更高精度
|
||||
```
|
||||
|
||||
### 修改渲染设置
|
||||
|
||||
```python
|
||||
scene.render.resolution_x = 3840 # 4K分辨率
|
||||
scene.render.resolution_y = 2160
|
||||
@@ -123,50 +144,58 @@ scene.render.resolution_y = 2160
|
||||
|
||||
### 常见问题
|
||||
|
||||
**Q: 找不到Blender**
|
||||
**Q: 找不到 Blender**
|
||||
|
||||
```
|
||||
❌ 错误:未找到Blender安装
|
||||
```
|
||||
A: 确保Blender已正确安装并添加到系统PATH中
|
||||
|
||||
A: 确保 Blender 已正确安装并添加到系统 PATH 中
|
||||
|
||||
**Q: 几何体创建失败**
|
||||
|
||||
```
|
||||
创建几何体时出错: ...
|
||||
```
|
||||
A: 检查JSON数据中的 `face_f` 和 `face_g` 参数是否为有效数值
|
||||
|
||||
A: 检查 JSON 数据中的 `face_f` 和 `face_g` 参数是否为有效数值
|
||||
|
||||
**Q: 导出失败**
|
||||
|
||||
```
|
||||
模型导出失败
|
||||
```
|
||||
|
||||
A: 确保有写入权限,检查磁盘空间
|
||||
|
||||
### 调试技巧
|
||||
|
||||
1. **查看详细日志**: 脚本会输出详细的创建过程
|
||||
2. **检查JSON数据**: 确保所有必需字段都存在
|
||||
3. **逐步运行**: 在Blender GUI中逐步执行脚本
|
||||
2. **检查 JSON 数据**: 确保所有必需字段都存在
|
||||
3. **逐步运行**: 在 Blender GUI 中逐步执行脚本
|
||||
|
||||
## 📈 性能优化
|
||||
|
||||
### 大型数据集
|
||||
- 对于超过100个对象的数据集,考虑分批处理
|
||||
|
||||
- 对于超过 100 个对象的数据集,考虑分批处理
|
||||
- 降低几何体分辨率以提高性能
|
||||
- 使用后台模式避免GUI开销
|
||||
- 使用后台模式避免 GUI 开销
|
||||
|
||||
### 内存使用
|
||||
- 大型模型可能需要8GB+内存
|
||||
- 监控内存使用,必要时重启Blender
|
||||
|
||||
- 大型模型可能需要 8GB+内存
|
||||
- 监控内存使用,必要时重启 Blender
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎提交Issue和Pull Request来改进这个工具!
|
||||
欢迎提交 Issue 和 Pull Request 来改进这个工具!
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用MIT许可证。
|
||||
本项目采用 MIT 许可证。
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
- Blender Foundation 提供的优秀3D建模软件
|
||||
- Blender Foundation 提供的优秀 3D 建模软件
|
||||
- 光学系统设计社区的支持和反馈
|
||||
157
README_fused_system.md
Normal file
157
README_fused_system.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# 融合光学系统脚本
|
||||
|
||||
这个脚本将 `toModel.py` 和 `light_path_simple.py` 两个脚本的功能融合在一起,在一个场景中同时显示光学系统的几何体和光路可视化。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- 🔧 **光学系统几何体**: 创建平面、抛物面、双曲面等光学元件
|
||||
- 💡 **光路可视化**: 显示发光的光路曲线
|
||||
- 🎨 **材质系统**: 金属、透明、发光等不同材质
|
||||
- 📁 **文件组织**: 使用集合(Collection)组织不同类型的对象
|
||||
- 📤 **多格式导出**: 支持 OBJ、GLB、Blend 文件导出
|
||||
- 🖼️ **高质量渲染**: 使用 Cycles 渲染引擎
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
├── fused_optical_system.py # 主要的融合脚本
|
||||
├── run_fused_system.py # 运行辅助脚本
|
||||
├── README_fused_system.md # 本说明文件
|
||||
├── e8caffb4622e03b1495bbc1ed13fce13.json # 光学系统数据
|
||||
└── miao_light_path_tsingtao.json # 光路数据
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 方法 1: 使用运行辅助脚本(推荐)
|
||||
|
||||
```bash
|
||||
python3 run_fused_system.py
|
||||
```
|
||||
|
||||
这个脚本会自动:
|
||||
|
||||
- 检测 Blender 安装
|
||||
- 检查必要的 JSON 文件
|
||||
- 运行融合脚本
|
||||
- 显示执行结果
|
||||
|
||||
### 方法 2: 直接使用 Blender 命令
|
||||
|
||||
```bash
|
||||
blender --background --python fused_optical_system.py -- [optical_json_path] [light_path_json_path]
|
||||
```
|
||||
|
||||
参数说明:
|
||||
|
||||
- `optical_json_path`: 光学系统 JSON 文件路径(可选,默认:`./e8caffb4622e03b1495bbc1ed13fce13.json`)
|
||||
- `light_path_json_path`: 光路 JSON 文件路径(可选,默认:`./miao_light_path_tsingtao.json`)
|
||||
|
||||
### 方法 3: 在 Blender 中运行
|
||||
|
||||
1. 打开 Blender
|
||||
2. 切换到 Scripting 工作区
|
||||
3. 打开 `fused_optical_system.py` 文件
|
||||
4. 点击运行按钮
|
||||
|
||||
## 输出文件
|
||||
|
||||
脚本执行完成后会生成以下文件:
|
||||
|
||||
- **`fused_optical_system.blend`** - Blender 工程文件,包含完整的场景
|
||||
- **`fused_optical_system.glb`** - Web 友好的 3D 模型格式
|
||||
- **`fused_optical_system.obj`** - 通用的 3D 模型格式
|
||||
- **`fused_optical_system_render.png`** - 高质量渲染图像
|
||||
|
||||
## 场景组织
|
||||
|
||||
融合后的场景使用集合(Collection)来组织对象:
|
||||
|
||||
- **OpticalSystem**: 包含所有光学系统几何体
|
||||
- **LightPaths**: 包含所有光路可视化对象
|
||||
|
||||
## 材质系统
|
||||
|
||||
- **金属材质**: 用于光学元件表面
|
||||
- **透明材质**: 用于"nothing"类型的对象
|
||||
- **发光材质**: 用于特殊发光对象
|
||||
- **光路材质**: 用于光路曲线,具有发光效果
|
||||
|
||||
## 光路可视化
|
||||
|
||||
- 支持多种颜色方案(红、绿、蓝、黄、紫、青、橙、粉)
|
||||
- 发光强度增强,确保在场景中清晰可见
|
||||
- 自动限制光路数量(最多 20 条)以避免场景过于复杂
|
||||
- 曲线厚度适中,既清晰又不会遮挡几何体
|
||||
|
||||
## 相机和灯光设置
|
||||
|
||||
- **相机位置**: (20, -20, 15),角度适合观察整个系统
|
||||
- **主灯光**: 太阳光,提供主要照明
|
||||
- **环境光**: 区域光,提供柔和的环境照明
|
||||
- **背景**: 深蓝色背景,突出光路效果
|
||||
|
||||
## 渲染设置
|
||||
|
||||
- **渲染引擎**: Cycles(提供更好的材质和光照效果)
|
||||
- **分辨率**: 1920x1080(全高清)
|
||||
- **输出格式**: PNG
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **找不到 Blender**
|
||||
|
||||
- 确保 Blender 已安装
|
||||
- 将 Blender 添加到系统 PATH 中
|
||||
- 或手动指定 Blender 安装路径
|
||||
|
||||
2. **缺少 JSON 文件**
|
||||
|
||||
- 确保 `e8caffb4622e03b1495bbc1ed13fce13.json` 存在
|
||||
- 确保 `miao_light_path_tsingtao.json` 存在
|
||||
|
||||
3. **脚本执行失败**
|
||||
|
||||
- 检查 JSON 文件格式是否正确
|
||||
- 查看错误输出信息
|
||||
- 确保有足够的磁盘空间
|
||||
|
||||
4. **渲染失败**
|
||||
- 检查是否有足够的系统内存
|
||||
- 确保输出目录可写
|
||||
- 检查 Blender 版本兼容性
|
||||
|
||||
### 调试模式
|
||||
|
||||
如果需要调试,可以在 Blender 中直接运行脚本,这样可以看到更详细的错误信息。
|
||||
|
||||
## 性能优化
|
||||
|
||||
- 光路数量限制在 20 条以内
|
||||
- 使用适当的几何体分辨率
|
||||
- 优化材质节点设置
|
||||
- 合理的灯光配置
|
||||
|
||||
## 扩展功能
|
||||
|
||||
可以基于这个融合脚本进一步扩展:
|
||||
|
||||
- 添加动画效果
|
||||
- 支持更多几何体类型
|
||||
- 自定义材质和纹理
|
||||
- 添加交互式控制
|
||||
- 支持实时渲染
|
||||
|
||||
## 技术细节
|
||||
|
||||
- **Python 版本**: 3.7+
|
||||
- **Blender 版本**: 2.80+
|
||||
- **依赖库**: bpy, json, mathutils, bmesh, numpy
|
||||
- **渲染引擎**: Cycles
|
||||
- **文件格式**: 支持 OBJ、GLB、Blend
|
||||
|
||||
## 许可证
|
||||
|
||||
本脚本遵循与原始脚本相同的许可证条款。
|
||||
278
README_light_path.md
Normal file
278
README_light_path.md
Normal file
@@ -0,0 +1,278 @@
|
||||
# 光学系统光路可视化
|
||||
|
||||
本项目提供了多种方式来可视化光学系统的光路数据,使用 Blender 生成高质量的 3D 光路模型。
|
||||
|
||||
## 文件说明
|
||||
|
||||
### 数据文件
|
||||
|
||||
- `miao_light_path_tsingtao.json` - 光路数据文件,包含多条光路的 3D 坐标点
|
||||
|
||||
### 可视化脚本
|
||||
|
||||
#### 基础版本
|
||||
|
||||
- `light_path_blender.py` - 基础版 Blender 光路可视化脚本
|
||||
- `run_light_path.py` - 运行基础版脚本的启动器
|
||||
|
||||
#### 增强版本
|
||||
|
||||
- `light_path_advanced.py` - 增强版 Blender 光路可视化脚本
|
||||
- `run_light_path_advanced.py` - 运行增强版脚本的启动器
|
||||
|
||||
#### 其他工具
|
||||
|
||||
- `linemodel.py` - 使用 matplotlib 的 2D/3D 光路可视化脚本
|
||||
|
||||
## 功能特点
|
||||
|
||||
### 基础版本功能
|
||||
|
||||
- ✅ 3D 光路曲线可视化
|
||||
- ✅ 不同颜色区分光路
|
||||
- ✅ 发光材质效果
|
||||
- ✅ 自动相机调整
|
||||
- ✅ 导出 GLB 和 Blend 文件
|
||||
- ✅ 渲染高质量图像
|
||||
|
||||
### 增强版本功能
|
||||
|
||||
- ✅ 所有基础版本功能
|
||||
- ✅ 光路起点和终点标记(绿色/红色球体)
|
||||
- ✅ 光路密度体积可视化
|
||||
- ✅ 更高质量的光照和材质
|
||||
- ✅ 更精确的相机控制
|
||||
- ✅ 更丰富的渲染选项
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 方法 1:使用运行脚本(推荐)
|
||||
|
||||
#### 基础版本
|
||||
|
||||
```bash
|
||||
python run_light_path.py
|
||||
```
|
||||
|
||||
#### 增强版本
|
||||
|
||||
```bash
|
||||
python run_light_path_advanced.py
|
||||
```
|
||||
|
||||
### 方法 2:直接在 Blender 中运行
|
||||
|
||||
1. 打开 Blender
|
||||
2. 切换到 Scripting 工作区
|
||||
3. 打开 `light_path_blender.py` 或 `light_path_advanced.py`
|
||||
4. 点击运行脚本
|
||||
|
||||
### 方法 3:命令行运行
|
||||
|
||||
```bash
|
||||
blender --background --python light_path_blender.py
|
||||
# 或
|
||||
blender --background --python light_path_advanced.py
|
||||
```
|
||||
|
||||
## 输出文件
|
||||
|
||||
### 基础版本输出
|
||||
|
||||
- `light_path_model.blend` - Blender 工程文件
|
||||
- `light_path_model.glb` - Web 友好格式(可在浏览器中查看)
|
||||
- `light_path_render.png` - 渲染图像
|
||||
|
||||
### 增强版本输出
|
||||
|
||||
- `light_path_advanced.blend` - Blender 工程文件
|
||||
- `light_path_advanced.glb` - Web 友好格式
|
||||
- `light_path_render.png` - 高质量渲染图像
|
||||
|
||||
## 系统要求
|
||||
|
||||
### 必需软件
|
||||
|
||||
- **Blender 3.0+** - 3D 建模和渲染软件
|
||||
- 下载地址:https://www.blender.org/download/
|
||||
- **Python 3.7+** - 编程语言环境
|
||||
|
||||
### 推荐配置
|
||||
|
||||
- **操作系统**: Windows 10+, macOS 10.15+, Ubuntu 18.04+
|
||||
- **内存**: 8GB+ RAM
|
||||
- **显卡**: 支持 OpenGL 3.3+的显卡
|
||||
- **存储**: 至少 2GB 可用空间
|
||||
|
||||
## 安装步骤
|
||||
|
||||
1. **安装 Blender**
|
||||
|
||||
```bash
|
||||
# macOS (使用Homebrew)
|
||||
brew install --cask blender
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt update
|
||||
sudo apt install blender
|
||||
|
||||
# Windows
|
||||
# 从官网下载安装包
|
||||
```
|
||||
|
||||
2. **验证安装**
|
||||
|
||||
```bash
|
||||
blender --version
|
||||
```
|
||||
|
||||
3. **运行脚本**
|
||||
```bash
|
||||
python run_light_path.py
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 1. 找不到 Blender
|
||||
|
||||
```
|
||||
❌ 错误:未找到Blender安装
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 确保 Blender 已正确安装
|
||||
- 将 Blender 添加到系统 PATH
|
||||
- 手动指定 Blender 路径
|
||||
|
||||
#### 2. 找不到数据文件
|
||||
|
||||
```
|
||||
❌ 错误:未找到光路数据文件 miao_light_path_tsingtao.json
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 确保数据文件在当前目录
|
||||
- 检查文件名是否正确
|
||||
|
||||
#### 3. 渲染失败
|
||||
|
||||
```
|
||||
❌ 渲染失败
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 检查显卡驱动是否最新
|
||||
- 降低渲染分辨率
|
||||
- 使用 Eevee 渲染引擎替代 Cycles
|
||||
|
||||
#### 4. 内存不足
|
||||
|
||||
```
|
||||
❌ 内存不足错误
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 关闭其他应用程序
|
||||
- 减少光路数量(修改脚本)
|
||||
- 增加系统虚拟内存
|
||||
|
||||
### 性能优化
|
||||
|
||||
#### 提高渲染速度
|
||||
|
||||
1. 使用 Eevee 渲染引擎
|
||||
2. 降低采样数量
|
||||
3. 减少光路数量
|
||||
4. 使用 GPU 渲染
|
||||
|
||||
#### 减少内存使用
|
||||
|
||||
1. 分批处理光路
|
||||
2. 简化几何体
|
||||
3. 优化材质设置
|
||||
|
||||
## 自定义配置
|
||||
|
||||
### 修改光路颜色
|
||||
|
||||
在脚本中修改 `base_colors` 列表:
|
||||
|
||||
```python
|
||||
base_colors = [
|
||||
(1.0, 0.2, 0.2, 1.0), # 红色
|
||||
(0.2, 1.0, 0.2, 1.0), # 绿色
|
||||
# 添加更多颜色...
|
||||
]
|
||||
```
|
||||
|
||||
### 调整光路粗细
|
||||
|
||||
修改 `thickness` 参数:
|
||||
|
||||
```python
|
||||
obj = create_light_path_curve(path, f"light_path_{i}", thickness=0.05)
|
||||
```
|
||||
|
||||
### 更改渲染质量
|
||||
|
||||
修改采样数量:
|
||||
|
||||
```python
|
||||
scene.cycles.samples = 256 # 更高的采样数 = 更好的质量
|
||||
```
|
||||
|
||||
## 技术细节
|
||||
|
||||
### 数据格式
|
||||
|
||||
光路数据采用 JSON 格式,结构如下:
|
||||
|
||||
```json
|
||||
[
|
||||
[
|
||||
[x1, y1, z1],
|
||||
[x2, y2, z2],
|
||||
...
|
||||
],
|
||||
[
|
||||
[x1, y1, z1],
|
||||
[x2, y2, z2],
|
||||
...
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
### 渲染引擎
|
||||
|
||||
- **Cycles**: 基于物理的渲染引擎,提供最真实的光照效果
|
||||
- **Eevee**: 实时渲染引擎,速度更快但质量稍低
|
||||
|
||||
### 导出格式
|
||||
|
||||
- **GLB**: 二进制 GLTF 格式,适合 Web 展示
|
||||
- **Blend**: Blender 原生格式,包含完整项目信息
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目采用 MIT 许可证,详见 LICENSE 文件。
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎提交 Issue 和 Pull Request 来改进这个项目!
|
||||
|
||||
## 联系方式
|
||||
|
||||
如有问题或建议,请通过以下方式联系:
|
||||
|
||||
- 提交 GitHub Issue
|
||||
- 发送邮件至项目维护者
|
||||
|
||||
---
|
||||
|
||||
**注意**: 确保在运行脚本前备份重要文件,脚本会生成新的文件并可能覆盖同名文件。
|
||||
69
circle.json
69
circle.json
@@ -35,7 +35,7 @@
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
0.0
|
||||
-5.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
@@ -44,9 +44,10 @@
|
||||
0.0
|
||||
],
|
||||
"name": "M00",
|
||||
"scale": 2,
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 5.0,
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
@@ -63,8 +64,9 @@
|
||||
0.0
|
||||
],
|
||||
"name": "M10",
|
||||
"scale": 2,
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
@@ -92,7 +94,7 @@
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
-1.0
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
@@ -111,7 +113,7 @@
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
-5.0
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
@@ -121,8 +123,9 @@
|
||||
],
|
||||
"name": "M01",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 5.0,
|
||||
"face_geometry": "circle",
|
||||
"scale": 2,
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
@@ -140,7 +143,8 @@
|
||||
],
|
||||
"name": "M11",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_geometry": "circle",
|
||||
"scale": 2,
|
||||
"face_f": 1.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
@@ -206,7 +210,7 @@
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
-5.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
@@ -216,17 +220,37 @@
|
||||
],
|
||||
"name": "M6",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 5.0,
|
||||
"face_geometry": "circle",
|
||||
"scale": 2.5,
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
-1.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "E0",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "nothing"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
@@ -235,30 +259,11 @@
|
||||
],
|
||||
"name": "M7",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "hyperbola",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1.0,
|
||||
"face_g": -6.875220831710909,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
-7.875220831710909
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "D0",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-1.9818052586129662,
|
||||
|
||||
339
circle.json.bak
Normal file
339
circle.json.bak
Normal file
@@ -0,0 +1,339 @@
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "",
|
||||
"children": [
|
||||
{
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "E0",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "nothing"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
-5.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "M00",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "M10",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 1.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-6.0,
|
||||
0.0,
|
||||
-5.974533048268448
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
-0.0,
|
||||
0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M20",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "E1",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "nothing"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "M01",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 5.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "M11",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 1.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
6.0,
|
||||
0.0,
|
||||
-5.974533048268448
|
||||
],
|
||||
"q": [
|
||||
0.0,
|
||||
-0.3826834323650898,
|
||||
0.0,
|
||||
0.9238795325112867
|
||||
],
|
||||
"name": "M21",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-1.9818052586129662,
|
||||
0.0,
|
||||
-5.974533048268448
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
0.0,
|
||||
-0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M30",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
1.9818052586129662,
|
||||
0.0,
|
||||
-5.974533048268448
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
-0.0,
|
||||
0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M31",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
-5.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "M6",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "parabola",
|
||||
"face_f": 5.0,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
-2.0
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "M7",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "hyperbola",
|
||||
"face_f": 1.0,
|
||||
"face_g": -6.875220831710909,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
0.0,
|
||||
0.0,
|
||||
-7.875220831710909
|
||||
],
|
||||
"q": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "D0",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-1.9818052586129662,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
0.0,
|
||||
-0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M40",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
-0.0,
|
||||
0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M50",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
1.9818052586129662,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
-0.0,
|
||||
0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M41",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
},
|
||||
{
|
||||
"p": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"q": [
|
||||
0.9238795325112867,
|
||||
0.0,
|
||||
-0.3826834323650898,
|
||||
0.0
|
||||
],
|
||||
"name": "M51",
|
||||
"face_type": "symm",
|
||||
"face_geometry": "circle",
|
||||
"face_f": 1e10,
|
||||
"face_g": 1e10,
|
||||
"draw_material": "metal"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
fused_optical_system.blend
Normal file
BIN
fused_optical_system.blend
Normal file
Binary file not shown.
BIN
fused_optical_system.blend1
Normal file
BIN
fused_optical_system.blend1
Normal file
Binary file not shown.
BIN
fused_optical_system.glb
Normal file
BIN
fused_optical_system.glb
Normal file
Binary file not shown.
559
fused_optical_system.py
Normal file
559
fused_optical_system.py
Normal file
@@ -0,0 +1,559 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
融合光学系统脚本
|
||||
将光学系统几何体和光路可视化合并到一个场景中
|
||||
|
||||
使用方法:
|
||||
blender --background --python fused_optical_system.py -- [optical_json_path] [light_path_json_path]
|
||||
|
||||
输出文件:
|
||||
- fused_optical_system.blend - Blender工程文件
|
||||
- fused_optical_system.glb - Web友好格式
|
||||
- fused_optical_system_render.png - 渲染图像
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import mathutils
|
||||
import os
|
||||
import bmesh
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
# 获取命令行参数
|
||||
def get_json_paths():
|
||||
"""从命令行参数获取JSON文件路径"""
|
||||
optical_json = "./e8caffb4622e03b1495bbc1ed13fce13.json"
|
||||
light_path_json = "./miao_light_path_tsingtao.json"
|
||||
|
||||
if len(sys.argv) > 5: # Blender传递的参数格式: blender --background --python script.py -- optical_json light_path_json
|
||||
# 查找 -- 分隔符后的参数
|
||||
for i, arg in enumerate(sys.argv):
|
||||
if arg == "--" and i + 1 < len(sys.argv):
|
||||
if i + 2 < len(sys.argv):
|
||||
optical_json = sys.argv[i + 1]
|
||||
light_path_json = sys.argv[i + 2]
|
||||
else:
|
||||
optical_json = sys.argv[i + 1]
|
||||
break
|
||||
|
||||
return optical_json, light_path_json
|
||||
|
||||
# 清空场景
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
|
||||
# 设置渲染引擎为Cycles(更好的材质渲染)
|
||||
bpy.context.scene.render.engine = 'CYCLES'
|
||||
|
||||
# 获取JSON文件路径
|
||||
optical_json_path, light_path_json_path = get_json_paths()
|
||||
print(f"光学系统JSON文件:{optical_json_path}")
|
||||
print(f"光路JSON文件:{light_path_json_path}")
|
||||
|
||||
# ==================== 光学系统几何体部分 ====================
|
||||
|
||||
def create_metal_material():
|
||||
"""创建金属材质"""
|
||||
mat = bpy.data.materials.new(name="metal")
|
||||
mat.use_nodes = True
|
||||
bsdf = mat.node_tree.nodes["Principled BSDF"]
|
||||
bsdf.inputs["Metallic"].default_value = 1.0
|
||||
bsdf.inputs["Roughness"].default_value = 0.2
|
||||
bsdf.inputs["Base Color"].default_value = (0.8, 0.8, 0.9, 1.0) # 淡蓝色金属
|
||||
return mat
|
||||
|
||||
def create_nothing_material():
|
||||
"""创建透明材质(用于 nothing)"""
|
||||
mat = bpy.data.materials.new(name="nothing")
|
||||
mat.use_nodes = True
|
||||
bsdf = mat.node_tree.nodes["Principled BSDF"]
|
||||
bsdf.inputs["Alpha"].default_value = 0.1
|
||||
bsdf.inputs["Base Color"].default_value = (1.0, 1.0, 1.0, 0.1)
|
||||
mat.blend_method = 'BLEND'
|
||||
mat.show_transparent_back = False
|
||||
return mat
|
||||
|
||||
def create_emissive_material():
|
||||
"""创建发光材质(用于特殊对象)"""
|
||||
mat = bpy.data.materials.new(name="emissive")
|
||||
mat.use_nodes = True
|
||||
bsdf = mat.node_tree.nodes["Principled BSDF"]
|
||||
try:
|
||||
if "Emission" in bsdf.inputs:
|
||||
bsdf.inputs["Emission"].default_value = (1.0, 0.8, 0.2, 1.0)
|
||||
elif "Emission Color" in bsdf.inputs:
|
||||
bsdf.inputs["Emission Color"].default_value = (1.0, 0.8, 0.2, 1.0)
|
||||
|
||||
if "Emission Strength" in bsdf.inputs:
|
||||
bsdf.inputs["Emission Strength"].default_value = 2.0
|
||||
else:
|
||||
# 备用方案:使用较亮的基础颜色
|
||||
bsdf.inputs["Base Color"].default_value = (1.0, 0.8, 0.2, 1.0)
|
||||
except Exception as e:
|
||||
print(f"设置发光材质时出错: {e}")
|
||||
# 备用方案:创建简单的明亮材质
|
||||
bsdf.inputs["Base Color"].default_value = (1.0, 0.8, 0.2, 1.0)
|
||||
bsdf.inputs["Roughness"].default_value = 0.1
|
||||
|
||||
return mat
|
||||
|
||||
def create_parabolic_surface(face_f, size=1.0, resolution=32):
|
||||
"""创建更精确的抛物面"""
|
||||
bm = bmesh.new()
|
||||
|
||||
# 创建抛物面网格
|
||||
for i in range(resolution):
|
||||
for j in range(resolution):
|
||||
u = (i / (resolution - 1) - 0.5) * size
|
||||
v = (j / (resolution - 1) - 0.5) * size
|
||||
|
||||
# 抛物面方程: z = (u^2 + v^2) / (4*f)
|
||||
if face_f > 0 and face_f < 1e9: # 避免除零和无限大
|
||||
z = (u*u + v*v) / (4 * face_f)
|
||||
else:
|
||||
z = 0
|
||||
|
||||
bm.verts.new((u, v, z))
|
||||
|
||||
bm.verts.ensure_lookup_table()
|
||||
|
||||
# 创建面
|
||||
for i in range(resolution - 1):
|
||||
for j in range(resolution - 1):
|
||||
v1 = i * resolution + j
|
||||
v2 = i * resolution + j + 1
|
||||
v3 = (i + 1) * resolution + j + 1
|
||||
v4 = (i + 1) * resolution + j
|
||||
|
||||
bm.faces.new([bm.verts[v1], bm.verts[v2], bm.verts[v3], bm.verts[v4]])
|
||||
|
||||
# 创建网格对象
|
||||
mesh = bpy.data.meshes.new("parabolic_surface")
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
|
||||
obj = bpy.data.objects.new("parabolic_surface", mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
|
||||
return obj
|
||||
|
||||
def create_hyperbolic_surface(face_f, face_g, size=1.0, resolution=32):
|
||||
"""创建双曲面"""
|
||||
bm = bmesh.new()
|
||||
|
||||
# 创建双曲面网格
|
||||
for i in range(resolution):
|
||||
for j in range(resolution):
|
||||
u = (i / (resolution - 1) - 0.5) * size
|
||||
v = (j / (resolution - 1) - 0.5) * size
|
||||
|
||||
# 双曲面方程: z^2/f^2 - (u^2 + v^2)/g^2 = 1
|
||||
if abs(face_g) > 0.1 and abs(face_f) > 0.1:
|
||||
try:
|
||||
z_squared = face_f * face_f * (1 + (u*u + v*v) / (face_g * face_g))
|
||||
if z_squared >= 0:
|
||||
z = (face_f if face_f > 0 else -face_f) * (z_squared ** 0.5)
|
||||
else:
|
||||
z = 0
|
||||
except:
|
||||
z = 0
|
||||
else:
|
||||
z = 0
|
||||
|
||||
bm.verts.new((u, v, z))
|
||||
|
||||
bm.verts.ensure_lookup_table()
|
||||
|
||||
# 创建面
|
||||
for i in range(resolution - 1):
|
||||
for j in range(resolution - 1):
|
||||
v1 = i * resolution + j
|
||||
v2 = i * resolution + j + 1
|
||||
v3 = (i + 1) * resolution + j + 1
|
||||
v4 = (i + 1) * resolution + j
|
||||
|
||||
bm.faces.new([bm.verts[v1], bm.verts[v2], bm.verts[v3], bm.verts[v4]])
|
||||
|
||||
mesh = bpy.data.meshes.new("hyperbolic_surface")
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
|
||||
obj = bpy.data.objects.new("hyperbolic_surface", mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
|
||||
return obj
|
||||
|
||||
def create_geometry(obj_data):
|
||||
"""根据面类型创建物体"""
|
||||
face_geom = obj_data.get("face_geometry", "plane")
|
||||
face_type = obj_data.get("face_type", "")
|
||||
name = obj_data.get("name", "noname")
|
||||
pos = obj_data["p"]
|
||||
quat = obj_data["q"]
|
||||
material_name = obj_data.get("draw_material", "metal")
|
||||
face_f = obj_data.get("face_f", 1.0)
|
||||
face_g = obj_data.get("face_g", 1.0)
|
||||
scale = obj_data.get("scale", 1.0)
|
||||
print(f"创建光学对象: {name} ({face_geom})")
|
||||
|
||||
mesh = None
|
||||
|
||||
try:
|
||||
if face_geom == "plane":
|
||||
# 创建圆形平面而不是方形
|
||||
bpy.ops.mesh.primitive_circle_add(vertices=32, radius=0.5)
|
||||
mesh = bpy.context.active_object
|
||||
# 填充圆形
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.edge_face_add()
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
elif face_geom == "circle":
|
||||
# 创建圆形平面
|
||||
radius = 0.5 * scale
|
||||
bpy.ops.mesh.primitive_circle_add(vertices=32, radius=radius)
|
||||
mesh = bpy.context.active_object
|
||||
# 填充圆形
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.edge_face_add()
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
elif face_geom == "parabola":
|
||||
if face_f < 1e9 and face_f > 0.1: # 使用精确抛物面
|
||||
mesh = create_parabolic_surface(face_f)
|
||||
else: # 使用简化圆锥
|
||||
bpy.ops.mesh.primitive_cone_add(vertices=32, radius1=0.75, radius2=0.05, depth=1.0)
|
||||
mesh = bpy.context.active_object
|
||||
elif face_geom == "hyperbola":
|
||||
if abs(face_f) > 0.1 and abs(face_g) > 0.1: # 使用精确双曲面
|
||||
mesh = create_hyperbolic_surface(face_f, face_g)
|
||||
else: # 使用简化环面
|
||||
bpy.ops.mesh.primitive_torus_add(major_radius=0.5, minor_radius=0.15)
|
||||
mesh = bpy.context.active_object
|
||||
else:
|
||||
# 默认立方体
|
||||
bpy.ops.mesh.primitive_cube_add(size=0.5)
|
||||
mesh = bpy.context.active_object
|
||||
except Exception as e:
|
||||
print(f"创建几何体时出错: {e}")
|
||||
# 备用:创建简单立方体
|
||||
bpy.ops.mesh.primitive_cube_add(size=0.25)
|
||||
mesh = bpy.context.active_object
|
||||
|
||||
# 设置对象属性
|
||||
mesh.name = name
|
||||
mesh.location = pos
|
||||
mesh.rotation_mode = 'QUATERNION'
|
||||
mesh.rotation_quaternion = mathutils.Quaternion(quat)
|
||||
|
||||
# 设置材质
|
||||
if material_name == "metal":
|
||||
mesh.data.materials.append(metal_mat)
|
||||
elif material_name == "nothing":
|
||||
mesh.data.materials.append(nothing_mat)
|
||||
else:
|
||||
mesh.data.materials.append(emissive_mat)
|
||||
|
||||
return mesh
|
||||
|
||||
# ==================== 光路可视化部分 ====================
|
||||
|
||||
def create_light_path_material(color=(1.0, 0.2, 0.2, 1.0)):
|
||||
"""创建光路材质"""
|
||||
mat = bpy.data.materials.new(name="light_path")
|
||||
mat.use_nodes = True
|
||||
nodes = mat.node_tree.nodes
|
||||
links = mat.node_tree.links
|
||||
|
||||
# 清除默认节点
|
||||
nodes.clear()
|
||||
|
||||
# 创建发光节点
|
||||
emission = nodes.new(type='ShaderNodeEmission')
|
||||
emission.inputs['Color'].default_value = color
|
||||
emission.inputs['Strength'].default_value = 2.0 # 增强发光强度
|
||||
|
||||
# 创建输出节点
|
||||
output = nodes.new(type='ShaderNodeOutputMaterial')
|
||||
|
||||
# 连接节点
|
||||
links.new(emission.outputs['Emission'], output.inputs['Surface'])
|
||||
|
||||
return mat
|
||||
|
||||
def create_light_path_curve(points, name="light_path"):
|
||||
"""创建光路曲线"""
|
||||
# 创建曲线数据
|
||||
curve_data = bpy.data.curves.new(name, type='CURVE')
|
||||
curve_data.dimensions = '3D'
|
||||
curve_data.resolution_u = 12
|
||||
curve_data.bevel_depth = 0.03 # 稍微增加厚度
|
||||
curve_data.bevel_resolution = 4
|
||||
|
||||
# 创建样条线
|
||||
spline = curve_data.splines.new('POLY')
|
||||
spline.points.add(len(points) - 1)
|
||||
|
||||
# 设置点坐标
|
||||
for i, point in enumerate(points):
|
||||
spline.points[i].co = (point[0], point[1], point[2], 1.0)
|
||||
|
||||
# 创建曲线对象
|
||||
curve_obj = bpy.data.objects.new(name, curve_data)
|
||||
bpy.context.collection.objects.link(curve_obj)
|
||||
|
||||
return curve_obj
|
||||
|
||||
def create_light_paths(light_paths):
|
||||
"""创建所有光路"""
|
||||
objects = []
|
||||
|
||||
# 颜色方案
|
||||
colors = [
|
||||
(1.0, 0.2, 0.2, 1.0), # 红色
|
||||
(0.2, 1.0, 0.2, 1.0), # 绿色
|
||||
(0.2, 0.2, 1.0, 1.0), # 蓝色
|
||||
(1.0, 1.0, 0.2, 1.0), # 黄色
|
||||
(1.0, 0.2, 1.0, 1.0), # 紫色
|
||||
(0.2, 1.0, 1.0, 1.0), # 青色
|
||||
(1.0, 0.6, 0.2, 1.0), # 橙色
|
||||
(0.8, 0.2, 0.8, 1.0), # 粉色
|
||||
]
|
||||
|
||||
# 限制光路数量以避免场景过于复杂
|
||||
max_paths = min(20, len(light_paths))
|
||||
print(f"创建前 {max_paths} 条光路(总共 {len(light_paths)} 条)")
|
||||
|
||||
for i, path in enumerate(light_paths[:max_paths]):
|
||||
if len(path) < 2:
|
||||
continue
|
||||
|
||||
# 选择颜色
|
||||
color = colors[i % len(colors)]
|
||||
|
||||
# 创建材质
|
||||
material = create_light_path_material(color)
|
||||
|
||||
# 创建光路对象
|
||||
obj = create_light_path_curve(path, f"light_path_{i}")
|
||||
|
||||
# 应用材质
|
||||
obj.data.materials.append(material)
|
||||
|
||||
objects.append(obj)
|
||||
|
||||
print(f"创建光路 {i+1}: {len(path)} 个点")
|
||||
|
||||
return objects
|
||||
|
||||
# ==================== 主程序 ====================
|
||||
|
||||
def load_optical_system_data(json_path):
|
||||
"""加载光学系统数据"""
|
||||
try:
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
print(f"✅ 成功加载光学系统JSON文件:{json_path}")
|
||||
print(f"包含 {len(data['children'])} 个光学对象")
|
||||
return data
|
||||
except FileNotFoundError:
|
||||
print(f"❌ 错误:找不到光学系统JSON文件 {json_path}")
|
||||
return None
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"❌ 错误:光学系统JSON文件格式错误 {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ 错误:加载光学系统JSON文件时出错 {e}")
|
||||
return None
|
||||
|
||||
def load_light_path_data(json_path):
|
||||
"""加载光路数据"""
|
||||
try:
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
print(f"✅ 成功加载光路JSON文件:{json_path}")
|
||||
print(f"包含 {len(data)} 条光路")
|
||||
return data
|
||||
except FileNotFoundError:
|
||||
print(f"❌ 错误:找不到光路JSON文件 {json_path}")
|
||||
return None
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"❌ 错误:光路JSON文件格式错误 {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ 错误:加载光路JSON文件时出错 {e}")
|
||||
return None
|
||||
|
||||
def setup_scene():
|
||||
"""设置场景"""
|
||||
# 添加相机
|
||||
bpy.ops.object.camera_add(location=(20, -20, 15))
|
||||
camera = bpy.context.active_object
|
||||
camera.rotation_euler = (1.0, 0, 0.785)
|
||||
bpy.context.scene.camera = camera
|
||||
|
||||
# 添加主灯光
|
||||
bpy.ops.object.light_add(type='SUN', location=(10, 10, 20))
|
||||
sun = bpy.context.active_object
|
||||
sun.data.energy = 3.0
|
||||
|
||||
# 添加环境光
|
||||
bpy.ops.object.light_add(type='AREA', location=(-10, -10, 15))
|
||||
area = bpy.context.active_object
|
||||
area.data.energy = 100.0
|
||||
area.data.size = 15.0
|
||||
|
||||
# 设置世界背景
|
||||
world = bpy.context.scene.world
|
||||
if world is None:
|
||||
world = bpy.data.worlds.new("World")
|
||||
bpy.context.scene.world = world
|
||||
|
||||
world.use_nodes = True
|
||||
bg_node = world.node_tree.nodes['Background']
|
||||
bg_node.inputs['Color'].default_value = (0.02, 0.02, 0.05, 1.0) # 深蓝色背景
|
||||
bg_node.inputs['Strength'].default_value = 0.3
|
||||
|
||||
def export_model(optical_objects, light_path_objects):
|
||||
"""导出模型"""
|
||||
print(f"准备导出 {len(optical_objects)} 个光学对象和 {len(light_path_objects)} 条光路...")
|
||||
|
||||
all_objects = optical_objects + light_path_objects
|
||||
|
||||
if not all_objects:
|
||||
print("警告:没有创建任何对象,跳过导出")
|
||||
return
|
||||
|
||||
# 选择所有创建的对象
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
for obj in all_objects:
|
||||
if obj and obj.name in bpy.data.objects:
|
||||
obj.select_set(True)
|
||||
print(f"已选择对象: {obj.name}")
|
||||
|
||||
try:
|
||||
# 导出为OBJ格式
|
||||
obj_path = os.path.abspath("./fused_optical_system.obj")
|
||||
bpy.ops.export_scene.obj(filepath=obj_path, use_selection=True, use_materials=True)
|
||||
print(f"模型已导出为: {obj_path}")
|
||||
except Exception as e:
|
||||
print(f"OBJ导出失败: {e}")
|
||||
|
||||
try:
|
||||
# 导出为GLB格式(适合web展示)
|
||||
glb_path = os.path.abspath("./fused_optical_system.glb")
|
||||
bpy.ops.export_scene.gltf(filepath=glb_path, use_selection=True, export_materials='EXPORT')
|
||||
print(f"模型已导出为: {glb_path}")
|
||||
except Exception as e:
|
||||
print(f"GLB导出失败: {e}")
|
||||
|
||||
try:
|
||||
# 保存Blender文件
|
||||
blend_path = os.path.abspath("./fused_optical_system.blend")
|
||||
bpy.ops.wm.save_as_mainfile(filepath=blend_path)
|
||||
print(f"Blender文件已保存为: {blend_path}")
|
||||
except Exception as e:
|
||||
print(f"Blender文件保存失败: {e}")
|
||||
|
||||
def render_image():
|
||||
"""渲染图像"""
|
||||
try:
|
||||
render_path = os.path.abspath("./fused_optical_system_render.png")
|
||||
scene = bpy.context.scene
|
||||
scene.render.filepath = render_path
|
||||
scene.render.resolution_x = 1920
|
||||
scene.render.resolution_y = 1080
|
||||
scene.render.image_settings.file_format = 'PNG'
|
||||
|
||||
print(f"开始渲染到: {render_path}")
|
||||
bpy.ops.render.render(write_still=True)
|
||||
print(f"渲染图像已保存为: {render_path}")
|
||||
except Exception as e:
|
||||
print(f"渲染失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🎨 融合光学系统脚本 - 几何体 + 光路可视化")
|
||||
print("=" * 50)
|
||||
|
||||
# 创建材质
|
||||
global metal_mat, nothing_mat, emissive_mat
|
||||
metal_mat = create_metal_material()
|
||||
nothing_mat = create_nothing_material()
|
||||
emissive_mat = create_emissive_material()
|
||||
|
||||
# 加载光学系统数据
|
||||
optical_data = load_optical_system_data(optical_json_path)
|
||||
if not optical_data:
|
||||
print("❌ 无法加载光学系统数据,退出")
|
||||
return
|
||||
|
||||
# 加载光路数据
|
||||
light_path_data = load_light_path_data(light_path_json_path)
|
||||
if not light_path_data:
|
||||
print("❌ 无法加载光路数据,退出")
|
||||
return
|
||||
|
||||
# 创建集合来组织对象
|
||||
optical_collection = bpy.data.collections.new("OpticalSystem")
|
||||
light_path_collection = bpy.data.collections.new("LightPaths")
|
||||
bpy.context.scene.collection.children.link(optical_collection)
|
||||
bpy.context.scene.collection.children.link(light_path_collection)
|
||||
|
||||
# 创建光学系统几何体
|
||||
print("\n🔧 创建光学系统几何体...")
|
||||
optical_objects = []
|
||||
for i, child in enumerate(optical_data["children"]):
|
||||
try:
|
||||
obj = create_geometry(child)
|
||||
optical_objects.append(obj)
|
||||
|
||||
# 将对象移动到专用集合
|
||||
bpy.context.collection.objects.unlink(obj)
|
||||
optical_collection.objects.link(obj)
|
||||
|
||||
except Exception as e:
|
||||
print(f"创建光学对象 {i} 时出错: {e}")
|
||||
|
||||
print(f"成功创建了 {len(optical_objects)} 个光学对象")
|
||||
|
||||
# 创建光路可视化
|
||||
print("\n💡 创建光路可视化...")
|
||||
light_path_objects = create_light_paths(light_path_data)
|
||||
|
||||
# 将光路对象移动到专用集合
|
||||
for obj in light_path_objects:
|
||||
bpy.context.collection.objects.unlink(obj)
|
||||
light_path_collection.objects.link(obj)
|
||||
|
||||
print(f"成功创建了 {len(light_path_objects)} 条光路")
|
||||
|
||||
# 设置场景
|
||||
print("\n🎬 设置场景...")
|
||||
setup_scene()
|
||||
|
||||
# 执行导出和渲染
|
||||
try:
|
||||
print("\n📤 开始导出模型...")
|
||||
export_model(optical_objects, light_path_objects)
|
||||
|
||||
print("\n🎨 开始渲染图像...")
|
||||
render_image()
|
||||
|
||||
print("\n🎉 脚本执行完成!")
|
||||
print("生成的文件:")
|
||||
print("- fused_optical_system.obj (3D模型)")
|
||||
print("- fused_optical_system.glb (Web友好格式)")
|
||||
print("- fused_optical_system.blend (Blender工程文件)")
|
||||
print("- fused_optical_system_render.png (渲染图像)")
|
||||
print(f"\n场景统计:")
|
||||
print(f"- 光学对象: {len(optical_objects)} 个")
|
||||
print(f"- 光路: {len(light_path_objects)} 条")
|
||||
|
||||
except Exception as e:
|
||||
print(f"执行导出/渲染时出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
fused_optical_system_render.png
Normal file
BIN
fused_optical_system_render.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
356
light_path_blender.py
Normal file
356
light_path_blender.py
Normal file
@@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
光路可视化Blender脚本
|
||||
读取miao_light_path_tsingtao.json文件并使用Blender绘制3D光路模型
|
||||
|
||||
使用方法:
|
||||
1. 在Blender中运行此脚本
|
||||
2. 或使用命令行: blender --background --python light_path_blender.py
|
||||
|
||||
输出文件:
|
||||
- light_path_model.blend - Blender工程文件
|
||||
- light_path_model.glb - Web友好格式
|
||||
- light_path_render.png - 渲染图像
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import mathutils
|
||||
import os
|
||||
import bmesh
|
||||
import numpy as np
|
||||
from mathutils import Vector
|
||||
|
||||
# 清空场景
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
|
||||
# 设置渲染引擎为Cycles(更好的材质渲染)
|
||||
bpy.context.scene.render.engine = 'CYCLES'
|
||||
|
||||
def load_light_paths(filename):
|
||||
"""加载光路数据"""
|
||||
try:
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
print(f"成功加载光路文件: {filename}")
|
||||
print(f"包含 {len(data)} 条光路")
|
||||
return data
|
||||
except Exception as e:
|
||||
print(f"加载光路文件失败: {e}")
|
||||
return []
|
||||
|
||||
def create_light_path_material(color=(1.0, 0.2, 0.2, 1.0), emission_strength=0.5):
|
||||
"""创建光路材质"""
|
||||
mat = bpy.data.materials.new(name="light_path")
|
||||
mat.use_nodes = True
|
||||
nodes = mat.node_tree.nodes
|
||||
links = mat.node_tree.links
|
||||
|
||||
# 清除默认节点
|
||||
nodes.clear()
|
||||
|
||||
# 创建发光节点
|
||||
emission = nodes.new(type='ShaderNodeEmission')
|
||||
emission.inputs['Color'].default_value = color
|
||||
emission.inputs['Strength'].default_value = emission_strength
|
||||
|
||||
# 创建输出节点
|
||||
output = nodes.new(type='ShaderNodeOutputMaterial')
|
||||
|
||||
# 连接节点
|
||||
links.new(emission.outputs['Emission'], output.inputs['Surface'])
|
||||
|
||||
return mat
|
||||
|
||||
def create_light_path_curve(points, name="light_path"):
|
||||
"""创建光路曲线"""
|
||||
# 创建曲线数据
|
||||
curve_data = bpy.data.curves.new(name, type='CURVE')
|
||||
curve_data.dimensions = '3D'
|
||||
curve_data.resolution_u = 12
|
||||
curve_data.bevel_depth = 0.02 # 光路粗细
|
||||
curve_data.bevel_resolution = 4
|
||||
|
||||
# 创建样条线
|
||||
spline = curve_data.splines.new('POLY')
|
||||
spline.points.add(len(points) - 1)
|
||||
|
||||
# 设置点坐标
|
||||
for i, point in enumerate(points):
|
||||
spline.points[i].co = (point[0], point[1], point[2], 1.0)
|
||||
|
||||
# 创建曲线对象
|
||||
curve_obj = bpy.data.objects.new(name, curve_data)
|
||||
bpy.context.collection.objects.link(curve_obj)
|
||||
|
||||
return curve_obj
|
||||
|
||||
def create_light_path_mesh(points, name="light_path"):
|
||||
"""创建光路网格(圆柱体连接)"""
|
||||
# 创建网格数据
|
||||
mesh_data = bpy.data.meshes.new(name)
|
||||
mesh_obj = bpy.data.objects.new(name, mesh_data)
|
||||
bpy.context.collection.objects.link(mesh_obj)
|
||||
|
||||
# 创建bmesh
|
||||
bm = bmesh.new()
|
||||
|
||||
# 为每段光路创建圆柱体
|
||||
for i in range(len(points) - 1):
|
||||
start_point = Vector(points[i])
|
||||
end_point = Vector(points[i + 1])
|
||||
|
||||
# 计算圆柱体参数
|
||||
direction = (end_point - start_point).normalized()
|
||||
length = (end_point - start_point).length
|
||||
radius = 0.02 # 光路半径
|
||||
|
||||
# 创建圆柱体
|
||||
bmesh.ops.create_cone(
|
||||
bm,
|
||||
segments=8,
|
||||
diameter1=radius,
|
||||
diameter2=radius,
|
||||
depth=length
|
||||
)
|
||||
|
||||
# 获取刚创建的圆柱体
|
||||
cylinder_verts = [v for v in bm.verts if v.select]
|
||||
cylinder_faces = [f for f in bm.faces if f.select]
|
||||
|
||||
# 取消选择
|
||||
for v in cylinder_verts:
|
||||
v.select = False
|
||||
for f in cylinder_faces:
|
||||
f.select = False
|
||||
|
||||
# 计算旋转
|
||||
up = Vector((0, 0, 1))
|
||||
if abs(direction.dot(up)) > 0.99:
|
||||
up = Vector((0, 1, 0))
|
||||
|
||||
rotation = direction.rotation_difference(up)
|
||||
|
||||
# 应用变换
|
||||
center = (start_point + end_point) / 2
|
||||
for v in cylinder_verts:
|
||||
v.co = rotation @ v.co + center
|
||||
|
||||
# 转换为网格
|
||||
bm.to_mesh(mesh_data)
|
||||
bm.free()
|
||||
|
||||
return mesh_obj
|
||||
|
||||
def create_light_path_objects(light_paths):
|
||||
"""创建所有光路对象"""
|
||||
objects = []
|
||||
|
||||
# 创建材质
|
||||
base_colors = [
|
||||
(1.0, 0.2, 0.2, 1.0), # 红色
|
||||
(0.2, 1.0, 0.2, 1.0), # 绿色
|
||||
(0.2, 0.2, 1.0, 1.0), # 蓝色
|
||||
(1.0, 1.0, 0.2, 1.0), # 黄色
|
||||
(1.0, 0.2, 1.0, 1.0), # 紫色
|
||||
(0.2, 1.0, 1.0, 1.0), # 青色
|
||||
(1.0, 0.5, 0.2, 1.0), # 橙色
|
||||
(0.5, 0.2, 1.0, 1.0), # 紫罗兰
|
||||
]
|
||||
|
||||
for i, path in enumerate(light_paths):
|
||||
if len(path) < 2:
|
||||
continue
|
||||
|
||||
# 选择颜色
|
||||
color = base_colors[i % len(base_colors)]
|
||||
|
||||
# 创建材质
|
||||
material = create_light_path_material(color, emission_strength=0.3)
|
||||
|
||||
# 创建光路对象(使用曲线)
|
||||
obj = create_light_path_curve(path, f"light_path_{i}")
|
||||
|
||||
# 应用材质
|
||||
obj.data.materials.append(material)
|
||||
|
||||
objects.append(obj)
|
||||
|
||||
print(f"创建光路 {i+1}: {len(path)} 个点")
|
||||
|
||||
return objects
|
||||
|
||||
def setup_scene():
|
||||
"""设置场景(相机、灯光等)"""
|
||||
# 添加相机
|
||||
bpy.ops.object.camera_add(location=(10, -10, 8))
|
||||
camera = bpy.context.active_object
|
||||
camera.rotation_euler = (1.0, 0, 0.785)
|
||||
bpy.context.scene.camera = camera
|
||||
|
||||
# 添加主灯光
|
||||
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
|
||||
sun = bpy.context.active_object
|
||||
sun.data.energy = 2.0
|
||||
|
||||
# 添加环境光
|
||||
bpy.ops.object.light_add(type='AREA', location=(-5, -5, 8))
|
||||
area = bpy.context.active_object
|
||||
area.data.energy = 30.0
|
||||
area.data.size = 8.0
|
||||
|
||||
# 设置世界背景为深色
|
||||
world = bpy.context.scene.world
|
||||
world.use_nodes = True
|
||||
bg_node = world.node_tree.nodes['Background']
|
||||
bg_node.inputs['Color'].default_value = (0.05, 0.05, 0.1, 1.0)
|
||||
bg_node.inputs['Strength'].default_value = 0.5
|
||||
|
||||
def calculate_bounds(light_paths):
|
||||
"""计算光路的边界框"""
|
||||
if not light_paths:
|
||||
return None
|
||||
|
||||
all_points = []
|
||||
for path in light_paths:
|
||||
all_points.extend(path)
|
||||
|
||||
all_points = np.array(all_points)
|
||||
|
||||
min_coords = all_points.min(axis=0)
|
||||
max_coords = all_points.max(axis=0)
|
||||
|
||||
return min_coords, max_coords
|
||||
|
||||
def adjust_camera_to_bounds(min_coords, max_coords):
|
||||
"""根据边界调整相机位置"""
|
||||
center = (min_coords + max_coords) / 2
|
||||
size = max_coords - min_coords
|
||||
max_size = max(size)
|
||||
|
||||
# 计算相机距离
|
||||
distance = max_size * 2.5
|
||||
|
||||
# 设置相机位置
|
||||
camera = bpy.context.scene.camera
|
||||
camera.location = center + Vector((distance, -distance, distance * 0.8))
|
||||
|
||||
# 让相机看向中心
|
||||
direction = center - camera.location
|
||||
rot_quat = direction.to_track_quat('-Z', 'Y')
|
||||
camera.rotation_euler = rot_quat.to_euler()
|
||||
|
||||
def export_model(objects):
|
||||
"""导出模型"""
|
||||
if not objects:
|
||||
print("警告:没有创建任何对象,跳过导出")
|
||||
return
|
||||
|
||||
# 选择所有光路对象
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
for obj in objects:
|
||||
if obj and obj.name in bpy.data.objects:
|
||||
obj.select_set(True)
|
||||
|
||||
try:
|
||||
# 导出为GLB格式
|
||||
glb_path = os.path.abspath("./light_path_model.glb")
|
||||
bpy.ops.export_scene.gltf(
|
||||
filepath=glb_path,
|
||||
use_selection=True,
|
||||
export_materials='EXPORT',
|
||||
export_lights=True
|
||||
)
|
||||
print(f"模型已导出为: {glb_path}")
|
||||
except Exception as e:
|
||||
print(f"GLB导出失败: {e}")
|
||||
|
||||
try:
|
||||
# 保存Blender文件
|
||||
blend_path = os.path.abspath("./light_path_model.blend")
|
||||
bpy.ops.wm.save_as_mainfile(filepath=blend_path)
|
||||
print(f"Blender文件已保存为: {blend_path}")
|
||||
except Exception as e:
|
||||
print(f"Blender文件保存失败: {e}")
|
||||
|
||||
def render_image():
|
||||
"""渲染图像"""
|
||||
try:
|
||||
# 设置渲染参数
|
||||
scene = bpy.context.scene
|
||||
scene.render.resolution_x = 1920
|
||||
scene.render.resolution_y = 1080
|
||||
scene.render.image_settings.file_format = 'PNG'
|
||||
scene.render.film_transparent = False
|
||||
|
||||
render_path = os.path.abspath("./light_path_render.png")
|
||||
scene.render.filepath = render_path
|
||||
print(f"开始渲染到: {render_path}")
|
||||
bpy.ops.render.render(write_still=True)
|
||||
print(f"渲染图像已保存为: {render_path}")
|
||||
except Exception as e:
|
||||
print(f"渲染失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🎨 光学系统光路可视化")
|
||||
print("=" * 40)
|
||||
|
||||
# 加载光路数据
|
||||
light_paths = load_light_paths("miao_light_path_tsingtao.json")
|
||||
|
||||
if not light_paths:
|
||||
print("❌ 无法加载光路数据")
|
||||
return
|
||||
|
||||
# 分析数据
|
||||
print(f"\n=== 光路数据分析 ===")
|
||||
print(f"总光路数量: {len(light_paths)}")
|
||||
|
||||
# 统计每条光路的点数
|
||||
path_lengths = [len(path) for path in light_paths]
|
||||
print(f"光路点数统计:")
|
||||
print(f" 最少点数: {min(path_lengths)}")
|
||||
print(f" 最多点数: {max(path_lengths)}")
|
||||
print(f" 平均点数: {np.mean(path_lengths):.2f}")
|
||||
|
||||
# 计算边界
|
||||
bounds = calculate_bounds(light_paths)
|
||||
if bounds:
|
||||
min_coords, max_coords = bounds
|
||||
print(f"\n坐标范围:")
|
||||
print(f" X: [{min_coords[0]:.3f}, {max_coords[0]:.3f}]")
|
||||
print(f" Y: [{min_coords[1]:.3f}, {max_coords[1]:.3f}]")
|
||||
print(f" Z: [{min_coords[2]:.3f}, {max_coords[2]:.3f}]")
|
||||
|
||||
# 创建光路对象
|
||||
print(f"\n正在创建光路对象...")
|
||||
light_path_objects = create_light_path_objects(light_paths)
|
||||
|
||||
# 设置场景
|
||||
print("正在设置场景...")
|
||||
setup_scene()
|
||||
|
||||
# 调整相机
|
||||
if bounds:
|
||||
adjust_camera_to_bounds(bounds[0], bounds[1])
|
||||
|
||||
# 导出模型
|
||||
print("正在导出模型...")
|
||||
export_model(light_path_objects)
|
||||
|
||||
# 渲染图像
|
||||
print("正在渲染图像...")
|
||||
render_image()
|
||||
|
||||
print("\n🎉 任务完成!")
|
||||
print("\n生成的文件:")
|
||||
print("- light_path_model.blend: Blender工程文件")
|
||||
print("- light_path_model.glb: Web友好格式")
|
||||
print("- light_path_render.png: 渲染图像")
|
||||
print(f"\n成功创建了 {len(light_path_objects)} 条光路")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
light_path_render.png
Normal file
BIN
light_path_render.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
light_path_simple.blend
Normal file
BIN
light_path_simple.blend
Normal file
Binary file not shown.
BIN
light_path_simple.glb
Normal file
BIN
light_path_simple.glb
Normal file
Binary file not shown.
200
light_path_simple.py
Normal file
200
light_path_simple.py
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
光路可视化Blender脚本
|
||||
读取miao_light_path_tsingtao.json文件并使用Blender绘制3D光路模型
|
||||
|
||||
使用方法:
|
||||
blender --background --python light_path_simple.py
|
||||
|
||||
输出文件:
|
||||
- light_path_simple.blend - Blender工程文件
|
||||
- light_path_simple.glb - Web友好格式
|
||||
- light_path_simple_render.png - 渲染图像
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
# 清空场景
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
|
||||
def load_light_paths(filename):
|
||||
"""加载光路数据"""
|
||||
try:
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
print(f"成功加载光路文件: {filename}")
|
||||
print(f"包含 {len(data)} 条光路")
|
||||
return data
|
||||
except Exception as e:
|
||||
print(f"加载光路文件失败: {e}")
|
||||
return []
|
||||
|
||||
def create_light_path_material(color=(1.0, 0.2, 0.2, 1.0)):
|
||||
"""创建光路材质"""
|
||||
mat = bpy.data.materials.new(name="light_path")
|
||||
mat.use_nodes = True
|
||||
nodes = mat.node_tree.nodes
|
||||
links = mat.node_tree.links
|
||||
|
||||
# 清除默认节点
|
||||
nodes.clear()
|
||||
|
||||
# 创建发光节点
|
||||
emission = nodes.new(type='ShaderNodeEmission')
|
||||
emission.inputs['Color'].default_value = color
|
||||
emission.inputs['Strength'].default_value = 1.0
|
||||
|
||||
# 创建输出节点
|
||||
output = nodes.new(type='ShaderNodeOutputMaterial')
|
||||
|
||||
# 连接节点
|
||||
links.new(emission.outputs['Emission'], output.inputs['Surface'])
|
||||
|
||||
return mat
|
||||
|
||||
def create_light_path_curve(points, name="light_path"):
|
||||
"""创建光路曲线"""
|
||||
# 创建曲线数据
|
||||
curve_data = bpy.data.curves.new(name, type='CURVE')
|
||||
curve_data.dimensions = '3D'
|
||||
curve_data.resolution_u = 12
|
||||
curve_data.bevel_depth = 0.02
|
||||
curve_data.bevel_resolution = 4
|
||||
|
||||
# 创建样条线
|
||||
spline = curve_data.splines.new('POLY')
|
||||
spline.points.add(len(points) - 1)
|
||||
|
||||
# 设置点坐标
|
||||
for i, point in enumerate(points):
|
||||
spline.points[i].co = (point[0], point[1], point[2], 1.0)
|
||||
|
||||
# 创建曲线对象
|
||||
curve_obj = bpy.data.objects.new(name, curve_data)
|
||||
bpy.context.collection.objects.link(curve_obj)
|
||||
|
||||
return curve_obj
|
||||
|
||||
def create_light_paths(light_paths):
|
||||
"""创建所有光路"""
|
||||
objects = []
|
||||
|
||||
# 颜色方案
|
||||
colors = [
|
||||
(1.0, 0.2, 0.2, 1.0), # 红色
|
||||
(0.2, 1.0, 0.2, 1.0), # 绿色
|
||||
(0.2, 0.2, 1.0, 1.0), # 蓝色
|
||||
(1.0, 1.0, 0.2, 1.0), # 黄色
|
||||
(1.0, 0.2, 1.0, 1.0), # 紫色
|
||||
]
|
||||
|
||||
for i, path in enumerate(light_paths[len(light_paths):]):
|
||||
if len(path) < 2:
|
||||
continue
|
||||
|
||||
# 选择颜色
|
||||
color = colors[i % len(colors)]
|
||||
|
||||
# 创建材质
|
||||
material = create_light_path_material(color)
|
||||
|
||||
# 创建光路对象
|
||||
obj = create_light_path_curve(path, f"light_path_{i}")
|
||||
|
||||
# 应用材质
|
||||
obj.data.materials.append(material)
|
||||
|
||||
objects.append(obj)
|
||||
|
||||
print(f"创建光路 {i+1}: {len(path)} 个点")
|
||||
|
||||
return objects
|
||||
|
||||
def setup_scene():
|
||||
"""设置场景"""
|
||||
# 添加相机
|
||||
bpy.ops.object.camera_add(location=(10, -10, 8))
|
||||
camera = bpy.context.active_object
|
||||
camera.rotation_euler = (1.0, 0, 0.785)
|
||||
bpy.context.scene.camera = camera
|
||||
|
||||
# 添加灯光
|
||||
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
|
||||
sun = bpy.context.active_object
|
||||
sun.data.energy = 2.0
|
||||
|
||||
# 设置世界背景
|
||||
world = bpy.context.scene.world
|
||||
if world is None:
|
||||
world = bpy.data.worlds.new("World")
|
||||
bpy.context.scene.world = world
|
||||
|
||||
world.use_nodes = True
|
||||
bg_node = world.node_tree.nodes['Background']
|
||||
bg_node.inputs['Color'].default_value = (0.05, 0.05, 0.1, 1.0)
|
||||
bg_node.inputs['Strength'].default_value = 0.5
|
||||
|
||||
def save_files():
|
||||
"""保存文件"""
|
||||
try:
|
||||
# 保存Blender文件
|
||||
blend_path = os.path.abspath("./light_path_simple.blend")
|
||||
bpy.ops.wm.save_as_mainfile(filepath=blend_path)
|
||||
print(f"Blender文件已保存为: {blend_path}")
|
||||
|
||||
# 导出GLB文件
|
||||
glb_path = os.path.abspath("./light_path_simple.glb")
|
||||
bpy.ops.export_scene.gltf(
|
||||
filepath=glb_path,
|
||||
export_materials='EXPORT'
|
||||
)
|
||||
print(f"GLB文件已导出为: {glb_path}")
|
||||
|
||||
# 渲染图像
|
||||
scene = bpy.context.scene
|
||||
scene.render.resolution_x = 1280
|
||||
scene.render.resolution_y = 720
|
||||
scene.render.image_settings.file_format = 'PNG'
|
||||
|
||||
render_path = os.path.abspath("./light_path_simple_render.png")
|
||||
scene.render.filepath = render_path
|
||||
bpy.ops.render.render(write_still=True)
|
||||
print(f"渲染图像已保存为: {render_path}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"保存文件时出错: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🎨 光学系统光路可视化 - 简化版")
|
||||
print("=" * 40)
|
||||
|
||||
# 加载光路数据
|
||||
light_paths = load_light_paths("miao_light_path_tsingtao.json")
|
||||
|
||||
if not light_paths:
|
||||
print("❌ 无法加载光路数据")
|
||||
return
|
||||
|
||||
print(f"处理前10条光路...")
|
||||
|
||||
# 创建光路对象
|
||||
light_path_objects = create_light_paths(light_paths)
|
||||
|
||||
# 设置场景
|
||||
setup_scene()
|
||||
|
||||
# 保存文件
|
||||
if save_files():
|
||||
print("\n🎉 任务完成!")
|
||||
print(f"成功创建了 {len(light_path_objects)} 条光路")
|
||||
else:
|
||||
print("\n❌ 保存文件失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
light_path_simple_render.png
Normal file
BIN
light_path_simple_render.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
17102
miao_light_path_tsingtao.json
Normal file
17102
miao_light_path_tsingtao.json
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1008 KiB After Width: | Height: | Size: 1008 KiB |
@@ -4,6 +4,7 @@ charset-normalizer==3.4.2
|
||||
Cython==3.1.2
|
||||
idna==3.10
|
||||
mathutils==3.3.0
|
||||
matplotlib==3.8.4
|
||||
numpy==1.26.4
|
||||
requests==2.32.4
|
||||
urllib3==2.5.0
|
||||
|
||||
132
run_fused_system.py
Normal file
132
run_fused_system.py
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
运行融合光学系统脚本的辅助脚本
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
def run_fused_optical_system():
|
||||
"""运行融合光学系统脚本"""
|
||||
|
||||
# 检查Blender是否可用
|
||||
blender_cmd = None
|
||||
|
||||
# 常见的Blender安装路径
|
||||
possible_paths = [
|
||||
"blender", # 如果在PATH中
|
||||
"/Applications/Blender.app/Contents/MacOS/Blender", # macOS
|
||||
"/usr/bin/blender", # Linux
|
||||
"C:\\Program Files\\Blender Foundation\\Blender\\blender.exe", # Windows
|
||||
]
|
||||
|
||||
for path in possible_paths:
|
||||
try:
|
||||
result = subprocess.run([path, "--version"],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if result.returncode == 0:
|
||||
blender_cmd = path
|
||||
print(f"✅ 找到Blender: {path}")
|
||||
break
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.SubprocessError):
|
||||
continue
|
||||
|
||||
if not blender_cmd:
|
||||
print("❌ 错误:找不到Blender安装")
|
||||
print("请确保Blender已安装并在PATH中,或者手动指定Blender路径")
|
||||
return False
|
||||
|
||||
# 检查必要的JSON文件
|
||||
optical_json = "./circle.json"
|
||||
light_path_json = "./miao_light_path_tsingtao.json"
|
||||
|
||||
missing_files = []
|
||||
if not os.path.exists(optical_json):
|
||||
missing_files.append(optical_json)
|
||||
if not os.path.exists(light_path_json):
|
||||
missing_files.append(light_path_json)
|
||||
|
||||
if missing_files:
|
||||
print(f"❌ 错误:缺少必要的JSON文件:{missing_files}")
|
||||
print("请确保以下文件存在:")
|
||||
print(f" - {optical_json}")
|
||||
print(f" - {light_path_json}")
|
||||
return False
|
||||
|
||||
# 检查融合脚本
|
||||
fused_script = "./fused_optical_system.py"
|
||||
if not os.path.exists(fused_script):
|
||||
print(f"❌ 错误:找不到融合脚本:{fused_script}")
|
||||
return False
|
||||
|
||||
print("🚀 开始运行融合光学系统脚本...")
|
||||
print(f"光学系统数据:{optical_json}")
|
||||
print(f"光路数据:{light_path_json}")
|
||||
print(f"Blender命令:{blender_cmd}")
|
||||
|
||||
try:
|
||||
# 运行Blender命令
|
||||
cmd = [
|
||||
blender_cmd,
|
||||
"--background", # 后台运行
|
||||
"--python", fused_script,
|
||||
"--", # 分隔符
|
||||
optical_json,
|
||||
light_path_json
|
||||
]
|
||||
|
||||
print(f"执行命令:{' '.join(cmd)}")
|
||||
|
||||
result = subprocess.run(cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=300) # 5分钟超时
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ 融合光学系统脚本执行成功!")
|
||||
print("\n输出文件:")
|
||||
print("- fused_optical_system.blend")
|
||||
print("- fused_optical_system.glb")
|
||||
print("- fused_optical_system.obj")
|
||||
print("- fused_optical_system_render.png")
|
||||
|
||||
# 显示脚本输出
|
||||
if result.stdout:
|
||||
print("\n脚本输出:")
|
||||
print(result.stdout)
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 融合光学系统脚本执行失败,返回码:{result.returncode}")
|
||||
if result.stderr:
|
||||
print("错误输出:")
|
||||
print(result.stderr)
|
||||
if result.stdout:
|
||||
print("标准输出:")
|
||||
print(result.stdout)
|
||||
return False
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("❌ 脚本执行超时(超过5分钟)")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 执行过程中出错:{e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🎨 融合光学系统脚本运行器")
|
||||
print("=" * 40)
|
||||
|
||||
success = run_fused_optical_system()
|
||||
|
||||
if success:
|
||||
print("\n🎉 任务完成!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n❌ 任务失败!")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
155
run_light_path.py
Normal file
155
run_light_path.py
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
运行光路可视化脚本
|
||||
使用Blender生成光学系统光路模型
|
||||
|
||||
使用方法:
|
||||
1. 确保已安装Blender
|
||||
2. 运行此脚本: python run_light_path.py
|
||||
|
||||
输出文件:
|
||||
- light_path_model.blend - Blender工程文件
|
||||
- light_path_model.glb - Web友好格式
|
||||
- light_path_render.png - 渲染图像
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
|
||||
def find_blender():
|
||||
"""查找Blender可执行文件"""
|
||||
system = platform.system()
|
||||
|
||||
common_paths = []
|
||||
if system == "Windows":
|
||||
common_paths = [
|
||||
r"C:\Program Files\Blender Foundation\Blender 3.6\blender.exe",
|
||||
r"C:\Program Files\Blender Foundation\Blender 4.0\blender.exe",
|
||||
r"C:\Program Files\Blender Foundation\Blender 4.1\blender.exe",
|
||||
r"C:\Program Files (x86)\Blender Foundation\Blender 3.6\blender.exe",
|
||||
]
|
||||
elif system == "Darwin": # macOS
|
||||
common_paths = [
|
||||
"/Applications/Blender.app/Contents/MacOS/Blender",
|
||||
"/usr/local/bin/blender",
|
||||
]
|
||||
elif system == "Linux":
|
||||
common_paths = [
|
||||
"/usr/bin/blender",
|
||||
"/usr/local/bin/blender",
|
||||
"/snap/bin/blender",
|
||||
]
|
||||
|
||||
# 首先尝试从PATH中找到blender
|
||||
try:
|
||||
result = subprocess.run(["which", "blender"], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 尝试常见路径
|
||||
for path in common_paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return None
|
||||
|
||||
def run_light_path_script():
|
||||
"""运行光路可视化Blender脚本"""
|
||||
blender_path = find_blender()
|
||||
|
||||
if not blender_path:
|
||||
print("❌ 错误:未找到Blender安装")
|
||||
print("\n请确保已安装Blender并且可以从命令行访问")
|
||||
print("下载地址: https://www.blender.org/download/")
|
||||
return False
|
||||
|
||||
print(f"✅ 找到Blender: {blender_path}")
|
||||
|
||||
# 检查必要文件
|
||||
script_path = os.path.abspath("light_path_blender.py")
|
||||
if not os.path.exists(script_path):
|
||||
print(f"❌ 错误:未找到脚本文件 {script_path}")
|
||||
return False
|
||||
|
||||
json_path = os.path.abspath("miao_light_path_tsingtao.json")
|
||||
if not os.path.exists(json_path):
|
||||
print(f"❌ 错误:未找到光路数据文件 {json_path}")
|
||||
return False
|
||||
|
||||
print("🚀 开始运行光路可视化脚本...")
|
||||
print("这可能需要几分钟时间,请耐心等待...")
|
||||
|
||||
try:
|
||||
# 运行Blender脚本
|
||||
cmd = [
|
||||
blender_path,
|
||||
"--background", # 后台运行
|
||||
"--python", script_path
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600) # 10分钟超时
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ 光路可视化脚本执行成功!")
|
||||
print("\n输出信息:")
|
||||
print(result.stdout)
|
||||
|
||||
# 检查生成的文件
|
||||
expected_files = [
|
||||
"light_path_model.blend",
|
||||
"light_path_model.glb",
|
||||
"light_path_render.png"
|
||||
]
|
||||
|
||||
print("\n📁 生成的文件:")
|
||||
for filename in expected_files:
|
||||
if os.path.exists(filename):
|
||||
size = os.path.getsize(filename)
|
||||
print(f"✅ {filename} ({size:,} bytes)")
|
||||
else:
|
||||
print(f"❌ {filename} (未找到)")
|
||||
|
||||
return True
|
||||
else:
|
||||
print("❌ 光路可视化脚本执行失败")
|
||||
print("错误输出:")
|
||||
print(result.stderr)
|
||||
if result.stdout:
|
||||
print("标准输出:")
|
||||
print(result.stdout)
|
||||
return False
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("❌ 脚本执行超时(超过10分钟)")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 执行时出错: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
print("🎨 光学系统光路可视化")
|
||||
print("=" * 40)
|
||||
print("使用Blender生成3D光路模型")
|
||||
print()
|
||||
|
||||
if run_light_path_script():
|
||||
print("\n🎉 任务完成!")
|
||||
print("\n您可以:")
|
||||
print("1. 使用Blender打开 light_path_model.blend 文件进行编辑")
|
||||
print("2. 在Web浏览器中查看 light_path_model.glb 文件")
|
||||
print("3. 查看渲染图像 light_path_render.png")
|
||||
print("\n光路模型特点:")
|
||||
print("- 每条光路使用不同颜色区分")
|
||||
print("- 发光材质效果,更真实的光线表现")
|
||||
print("- 3D曲线表示,支持多角度查看")
|
||||
print("- 自动调整相机位置以最佳角度展示")
|
||||
else:
|
||||
print("\n❌ 任务失败,请检查错误信息")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
169
run_light_path_advanced.py
Normal file
169
run_light_path_advanced.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
运行增强版光路可视化脚本
|
||||
使用Blender生成光学系统高级光路模型
|
||||
|
||||
功能特点:
|
||||
- 发光光路效果
|
||||
- 光路起点和终点标记
|
||||
- 光路密度可视化
|
||||
- 高质量渲染
|
||||
|
||||
使用方法:
|
||||
1. 确保已安装Blender
|
||||
2. 运行此脚本: python run_light_path_advanced.py
|
||||
|
||||
输出文件:
|
||||
- light_path_advanced.blend - Blender工程文件
|
||||
- light_path_advanced.glb - Web友好格式
|
||||
- light_path_render.png - 渲染图像
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
|
||||
def find_blender():
|
||||
"""查找Blender可执行文件"""
|
||||
system = platform.system()
|
||||
|
||||
common_paths = []
|
||||
if system == "Windows":
|
||||
common_paths = [
|
||||
r"C:\Program Files\Blender Foundation\Blender 3.6\blender.exe",
|
||||
r"C:\Program Files\Blender Foundation\Blender 4.0\blender.exe",
|
||||
r"C:\Program Files\Blender Foundation\Blender 4.1\blender.exe",
|
||||
r"C:\Program Files (x86)\Blender Foundation\Blender 3.6\blender.exe",
|
||||
]
|
||||
elif system == "Darwin": # macOS
|
||||
common_paths = [
|
||||
"/Applications/Blender.app/Contents/MacOS/Blender",
|
||||
"/usr/local/bin/blender",
|
||||
]
|
||||
elif system == "Linux":
|
||||
common_paths = [
|
||||
"/usr/bin/blender",
|
||||
"/usr/local/bin/blender",
|
||||
"/snap/bin/blender",
|
||||
]
|
||||
|
||||
# 首先尝试从PATH中找到blender
|
||||
try:
|
||||
result = subprocess.run(["which", "blender"], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 尝试常见路径
|
||||
for path in common_paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return None
|
||||
|
||||
def run_advanced_light_path_script():
|
||||
"""运行增强版光路可视化Blender脚本"""
|
||||
blender_path = find_blender()
|
||||
|
||||
if not blender_path:
|
||||
print("❌ 错误:未找到Blender安装")
|
||||
print("\n请确保已安装Blender并且可以从命令行访问")
|
||||
print("下载地址: https://www.blender.org/download/")
|
||||
return False
|
||||
|
||||
print(f"✅ 找到Blender: {blender_path}")
|
||||
|
||||
# 检查必要文件
|
||||
script_path = os.path.abspath("light_path_advanced.py")
|
||||
if not os.path.exists(script_path):
|
||||
print(f"❌ 错误:未找到脚本文件 {script_path}")
|
||||
return False
|
||||
|
||||
json_path = os.path.abspath("miao_light_path_tsingtao.json")
|
||||
if not os.path.exists(json_path):
|
||||
print(f"❌ 错误:未找到光路数据文件 {json_path}")
|
||||
return False
|
||||
|
||||
print("🚀 开始运行增强版光路可视化脚本...")
|
||||
print("这可能需要较长时间,请耐心等待...")
|
||||
print("增强版功能包括:")
|
||||
print("- 发光光路效果")
|
||||
print("- 起点和终点标记")
|
||||
print("- 光路密度可视化")
|
||||
print("- 高质量渲染")
|
||||
|
||||
try:
|
||||
# 运行Blender脚本
|
||||
cmd = [
|
||||
blender_path,
|
||||
"--background", # 后台运行
|
||||
"--python", script_path
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=900) # 15分钟超时
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ 增强版光路可视化脚本执行成功!")
|
||||
print("\n输出信息:")
|
||||
print(result.stdout)
|
||||
|
||||
# 检查生成的文件
|
||||
expected_files = [
|
||||
"light_path_advanced.blend",
|
||||
"light_path_advanced.glb",
|
||||
"light_path_render.png"
|
||||
]
|
||||
|
||||
print("\n📁 生成的文件:")
|
||||
for filename in expected_files:
|
||||
if os.path.exists(filename):
|
||||
size = os.path.getsize(filename)
|
||||
print(f"✅ {filename} ({size:,} bytes)")
|
||||
else:
|
||||
print(f"❌ {filename} (未找到)")
|
||||
|
||||
return True
|
||||
else:
|
||||
print("❌ 增强版光路可视化脚本执行失败")
|
||||
print("错误输出:")
|
||||
print(result.stderr)
|
||||
if result.stdout:
|
||||
print("标准输出:")
|
||||
print(result.stdout)
|
||||
return False
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("❌ 脚本执行超时(超过15分钟)")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 执行时出错: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
print("🎨 光学系统光路可视化 - 增强版")
|
||||
print("=" * 50)
|
||||
print("使用Blender生成高级3D光路模型")
|
||||
print()
|
||||
|
||||
if run_advanced_light_path_script():
|
||||
print("\n🎉 任务完成!")
|
||||
print("\n您可以:")
|
||||
print("1. 使用Blender打开 light_path_advanced.blend 文件进行编辑")
|
||||
print("2. 在Web浏览器中查看 light_path_advanced.glb 文件")
|
||||
print("3. 查看高质量渲染图像 light_path_render.png")
|
||||
print("\n增强版光路模型特点:")
|
||||
print("- 每条光路使用不同颜色和发光强度")
|
||||
print("- 绿色球体标记光路起点")
|
||||
print("- 红色球体标记光路终点")
|
||||
print("- 光路密度体积可视化")
|
||||
print("- 高质量Cycles渲染引擎")
|
||||
print("- 自动优化相机角度和光照")
|
||||
print("- 支持交互式3D查看")
|
||||
else:
|
||||
print("\n❌ 任务失败,请检查错误信息")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -68,8 +68,6 @@ def create_emissive_material():
|
||||
mat = bpy.data.materials.new(name="emissive")
|
||||
mat.use_nodes = True
|
||||
bsdf = mat.node_tree.nodes["Principled BSDF"]
|
||||
|
||||
# 在Blender 4.0+中,发光属性可能位置不同
|
||||
try:
|
||||
if "Emission" in bsdf.inputs:
|
||||
bsdf.inputs["Emission"].default_value = (1.0, 0.8, 0.2, 1.0)
|
||||
|
||||
Reference in New Issue
Block a user