Compare commits

...

8 Commits

Author SHA1 Message Date
nicomacbookpro
e876518844 readmexiugai 2025-09-04 08:51:38 +08:00
nicolas
86544c4d9b scale 2025-09-02 18:34:43 +08:00
nicolas
04c0eb0b9a circle 2025-09-02 18:32:37 +08:00
nicolas
ba7b249f48 xiugai 2025-09-02 17:51:49 +08:00
nicolas
a09c20bba6 circle 2025-09-02 17:51:40 +08:00
nicolas
85f2e82e12 circle 2025-09-02 17:43:22 +08:00
nicomacbookpro
ed37d800c2 readme 2025-09-02 15:59:18 +08:00
nicomacbookpro
565bb02a28 案例 2025-09-02 15:58:31 +08:00
17 changed files with 1292 additions and 62 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -13,22 +13,26 @@
## 📋 系统要求
- **Blender 3.6+** (推荐 4.0+)
- **Python 3.7+**
- **Python 3.11+**
- **操作系统**: Windows, macOS, Linux
## 🛠️ 安装
### 1. 安装 Blender
从官网下载并安装: https://www.blender.org/download/
### 2. 验证安装
```bash
# 确保可以从命令行访问Blender
blender --version
```
### 3. 准备数据文件
确保您的 JSON 数据文件格式正确,包含以下结构:
```json
{
"p": [0.0, 0.0, 0.0],
@@ -51,28 +55,37 @@ blender --version
## 🎯 使用方法
---------------------阅读到此请直接阅读 use.md 以下暂时废弃----------------------------------
### 方法 1: 使用运行脚本(推荐)
```bash
python run_blender.py -i jsonfile.json
```
### 方法 2: 直接运行 Blender 脚本
```bash
blender --background --python toModel.py
```
### 方法 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 工程文件,包含所有材质和设置 |
@@ -81,16 +94,19 @@ blender --background --python toModel.py
## ⚙️ 配置选项
### 几何体类型支持
- **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
@@ -124,21 +145,27 @@ scene.render.resolution_y = 2160
### 常见问题
**Q: 找不到 Blender**
```
❌ 错误未找到Blender安装
```
A: 确保 Blender 已正确安装并添加到系统 PATH 中
**Q: 几何体创建失败**
```
创建几何体时出错: ...
```
A: 检查 JSON 数据中的 `face_f``face_g` 参数是否为有效数值
**Q: 导出失败**
```
模型导出失败
```
A: 确保有写入权限,检查磁盘空间
### 调试技巧
@@ -150,11 +177,13 @@ A: 确保有写入权限,检查磁盘空间
## 📈 性能优化
### 大型数据集
- 对于超过 100 个对象的数据集,考虑分批处理
- 降低几何体分辨率以提高性能
- 使用后台模式避免 GUI 开销
### 内存使用
- 大型模型可能需要 8GB+内存
- 监控内存使用,必要时重启 Blender

157
README_fused_system.md Normal file
View 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
## 许可证
本脚本遵循与原始脚本相同的许可证条款。

View File

@@ -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
View 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

Binary file not shown.

BIN
fused_optical_system.blend1 Normal file

Binary file not shown.

BIN
fused_optical_system.glb Normal file

Binary file not shown.

559
fused_optical_system.py Normal file
View 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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

1
gl.json Normal file

File diff suppressed because one or more lines are too long

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

132
run_fused_system.py Normal file
View 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()

8
use.md Normal file
View File

@@ -0,0 +1,8 @@
# 先看 README.md 安装 blender
然后(最好虚拟环境 python version >=3.11
pip install -r requirements.txt
python3 run_fused_system.py
fused_optical_system.glb 为最终产出