☰
卡塞格林望远镜虚拟样机:VirtualLab与Unity集成仿真实践
2026/10/20 16:09:32 网站建设 项目流程

做卡塞格林望远镜的仿真和可视化,我前后折腾了小半个月,踩了一堆文档里不太会写的坑。这个项目让我印象很深的一点是:光学仿真软件和实时3D引擎各干各的专长,VirtualLab能把望远镜的衍射、像差、遮挡效应算到很细,但对非光学专业的人来说,一堆PSF曲线和波前图并不直观。Unity的好处是交互性强,用户能拖着滑块改参数、绕着镜筒转视角,可它本身不会做光学追迹。所以把这两个工具串起来,做一个“能算又能看”的卡塞格林望远镜虚拟样机,就成了一个很典型的项目。

如果你也在做光学教学演示、虚拟实验室,或者要给某个光学系统做数字样机,这篇文章里的思路可以直接借走。我会从卡塞格林望远镜的参数设计讲起,再讲VirtualLab建模流程、Unity集成方案,最后把实操中踩过的坑和排查方法一起列出来。

1. 卡塞格林望远镜的结构与参数设计:先搞清楚要仿真什么

卡塞格林望远镜不是“一个大镜子加一个小镜子”这么简单。它的光路要经过两次反射:平行光先打到主镜,被主镜反射后汇聚向主镜焦点方向,但在到达焦点之前被次镜截住,次镜再把光束反射回去,穿过主镜中心的开孔,最终在主镜背面成像。这种折叠光路最大的好处是:用不长的镜筒就能实现很长的系统焦距,比如一个一米左右的镜筒,光学焦距能做到两米甚至更长。

这个结构和折射式望远镜有一个根本性区别:光束在主镜和次镜之间走了两次,所以主镜中心必须开孔,这个孔本身就是一种孔径遮挡。中心遮挡会带来能量损失、衍射环能量外移、MTF中频下降等一系列现象。仿真卡塞格林系统时,最忌讳的就是只把两个镜面摆好,忽略中心遮挡。因为卡塞格林最典型的像质特征,恰恰都是由遮挡造成的。

1.1 卡塞格林结构的核心优势与选型依据

为什么选卡塞格林而不是牛顿式、格里高利式?这个问题在我一开始做项目时想过很久。牛顿式结构确实简单,一个平面副镜把光路折到镜筒侧面,但焦点不在主光轴上,探测器、光纤接口、后续光路都不太好布置,而且平面次镜也会遮挡一部分光。格里高利式用凹椭球次镜,像差校正有优势,但次镜到主镜的距离更长,镜筒会明显变长,系统整体不够紧凑。

卡塞格林在主镜中心开孔,焦平面在主镜正后方,探测器可以沿着光轴摆放,这在工程上是相当友好的。比如后面要接相机、光谱仪或者制冷探测器,都可以做同轴布局。与此同时,主镜用抛物面、次镜用双曲面,可以在近轴区域同时校正球差,让轴上点成像质量做到衍射极限附近。所以工作距离长、结构紧凑、同轴出光,这三个特点让卡塞格林成为反射式系统中应用最广的结构之一。

从虚拟仿真的角度来说,卡塞格林也是最合适的选择之一。它的光路折叠关系清晰,遮挡效应明显,参数调整对像质的影响可解释性强。用户拖动一个“次镜直径”的滑块,就能看到PSF从锐利变成带衍射环的拖尾图案,这种直观反馈在演示和教学中特别有用。要是换成折射系统,用户很难一眼看出像差来源。

1.2 参数初值怎么定:从系统焦距反推两镜间距

我建模仿真之前,先把几个关键参数定下来。最常用的设计起点是:主镜口径D、主镜焦距f1、系统焦距F、后截距b、遮挡比ε。这五个参数之间互相约束,改一个就得重新算另外几个。举例来说,我开始定的是口径200mm、主镜焦距600mm、系统焦距2000mm、后截距400mm。系统焦距除以主镜焦距,得到次镜放大率M,也就是2000除以600,约等于3.33。

两镜间距d和后截距b之间有个近轴关系:两镜间距d约等于(f1 - b/M)?实际推导要看符号约定,我习惯用近轴设计工具或VirtualLab里的内置示例处理,手算只用来验证数量级。按上面的数估算,主镜和次镜的间距大概在370mm量级,次镜的焦距为负值、顶点曲率半径在-600mm到-700mm量级。下面是我用的初值表,后续优化时以这个为起点:

参数符号初值
主镜口径D1200 mm
主镜焦距f1600 mm
系统焦距F2000 mm
后截距b400 mm
主镜-次镜间距d约370 mm
次镜焦距f2约-330 mm
次镜顶点曲率半径R2约-660 mm
次镜口径D260 mm

这里要特别提醒:R2=-660mm是球面初值,实际经典卡塞格林里次镜是凸双曲面,VirtualLab优化中会引入非球面系数。别指望球面初值直接达到衍射极限,后面一定要做面型优化。我做第一次仿真时直接用球面次镜,结果光斑明显偏大,还以为是建模错了,后来才意识到非球面系数没加上去。

1.3 遮挡比:卡塞格林最绕不开的设计变量

遮挡比ε定义为次镜口径D2除以主镜口径D1。它直接影响两个东西:一是系统实际通光面积,二是衍射能量分布。遮挡比越大,中心遮挡越严重,PSF主瓣能量占比越低,能量往衍射环扩散,MTF在中频区域会明显下降;但次镜太小又会带来支撑刚度和加工难度问题。工程上常见的遮挡比在0.2到0.4之间,我选了0.3。

在VirtualLab里做参数扫描时,遮挡比是一个特别有意思的变量。你把次镜半径从30mm扫到70mm,看PSF和MTF的变化,能很直观地理解光学书上说的“遮挡使衍射极限下MTF下降”是怎么回事。甚至当遮挡比接近0时,系统表现得像纯圆孔衍射;遮挡比增大后,PSF中心的艾里斑变窄但旁瓣能量变多。这种对比放在Unity交互场景里,用一个滑块让用户自己拖动,效果远比一张静态曲线图好。

2. VirtualLab中卡塞格林望远镜建模的三步走

VirtualLab建模的逻辑是“光源—光学元件—探测器”的光路树,卡塞格林系统比较特殊,光线不是简单的一路直走,而是两次反射后折返。第一次建模时,我按照折射系统的习惯把主镜和次镜依次排好,结果探测器一片空白。后来调整思路,把光路分成“入射段”和“反射段”,才把整个系统理清楚。

2.1 搭建光路模型:一次典型的非序列追迹

我实际搭建的步骤大概是这样的:先建一个平面波光源,波长设550nm,光束直径200mm,代表平行入射光。主镜放在坐标原点,面型选凹抛物面,口径用环形孔径,外半径100mm,内半径35mm。内径35mm是按次镜在焦平面上的投影略放宽之后取的,为了让次镜反射回来的光束能穿过主镜中心孔,同时也不至于产生额外的边缘衍射。

次镜放在主镜右侧约370mm处,面型选凸双曲面,口径60mm,反射方向设置成朝主镜方向。注意这里有个很关键的细节:从光源方向看过去,次镜本身就是中心遮挡体,所以光路里除了要有一个能反射的次镜面,还需要明确这个镜面的“背面”是遮挡的。VirtualLab中处理反射镜时,如果不小心,中央光束可能会直接透过次镜继续向前传播,导致后面的光路全乱掉。我的做法是在次镜位置加一个等尺寸的圆形吸收屏,等效模拟次镜对入射平行光的遮挡。

探测器放在主镜左侧400mm处,也就是“主镜后方”。这样才能接住被次镜反射回来、穿过主镜开孔的光束。探测器尺寸我设成10mm×10mm,像素128×128。这个尺寸要和后面仿真得到的PSF大小匹配,如果探测器开得太小,衍射环会被截断;开得太大又会浪费采样精度。

2.2 两种追迹模式:算得快和算得准

VirtualLab里常用的两种计算模式:光线追迹和场追迹。光线追迹速度快,适合检查光路走向、判断光线有没有打到镜面边缘,但它不包含衍射信息,算不出精细的PSF和MTF;场追迹走物理光学传播,能计算衍射和干涉,但计算量大。

我做卡塞格林望远镜时,先用光线追迹做光路验证,确认每一个元件的位置、法向、口径都没问题,屏幕上能看到光线走了一个“Z”字形从主镜到次镜再回到主镜后面。然后再切换到场追迹,计算探测器上的强度分布。这样能避免一上来就用场追迹,结果光路边都没走对,算了十几分钟全是无效数据。

这套流程很有必要。因为卡塞格林系统的光路是折返的,光线追迹阶段能直接看出很多低级问题,比如次镜法向反了、主镜开孔太小、探测器位置不对。把这些基础问题排掉之后再用场追迹,结果更有可信度。

2.3 结果怎么读:PSF、波前和MTF

VirtualLab的仿真结果一般看三个量:PSF、波前、MTF。

PSF是点光源通过系统后在探测器上的强度分布,能直观反映光能集中度。卡塞格林的PSF和纯圆孔衍射不一样,中心主瓣周围有一圈圈比较明显的衍射环,这是中心遮挡造成的。波前线能看出残余像差的类型:如果波前呈旋转对称的马鞍形,多半是球差;如果呈不对称倾斜,多半是彗差。MTF则是从PSF做傅里叶变换得到的,评价不同空间频率的对比度传递能力。

我推荐把三者对照着看。只看PSF很难判断像质是否到了衍射极限,但配合波前图和MTF曲线,就能知道系统离理想状态还差多少。特别是遮挡比改变之后,MTF中频下降这件事,单看PSF不直观,看MTF曲线就一目了然。

2.4 参数扫描:用一组仿真覆盖交互需求

项目后面要做Unity交互,我的方案是预计算,也就是提前在VirtualLab里算出一批不同参数下的PSF结果,Unity运行时只做查表和显示。那么这个“一批”就很重要,参数扫描直接决定交互数据的覆盖范围。

我做了两组扫描:第一组固定探测器在最佳焦面,改变次镜口径,从50mm到80mm,每隔5mm取一组数据;第二组固定次镜口径60mm,把探测器沿光轴前后移动,从-2mm到+2mm,每隔0.5mm取一组PSF。加起来大概二十多组数据,每组分四个参数,分别是最佳焦面、离焦-1mm、离焦-2mm、离焦+1mm之类。这些结果导出成CSV或纹理,之后给Unity用。

参数扫描有两点经验:一是先粗扫后细扫,别第一次就设置很细的步长,否则计算时间会让你失去耐心;二是保存PSF时要连空间步长一起保存,因为Unity里显示光斑大小时需要知道每个像素对应的实际尺寸。很多人在这一步只存了强度数组,没存坐标刻度,后面做尺寸匹配时会很被动。

3. VirtualLab结果往Unity里搬:数据接口与交互架构

这一节是整个项目里最容易失控的部分。VirtualLab是精密的光学工具,它算的是振幅、相位和完整的光场;Unity是实时渲染引擎,它追求的是60帧的流畅交互。两者之间的数据传递,不能简单粗暴地截个图贴上去,而是要把光学结果“翻译”成Unity能吃下的资源。

3.1 Unity能补位的部分:交互、3D和教学叙事

VirtualLab本身也能显示三维光路,但它的主要目标不是做面向用户的交互演示。你把一个包含光线追迹的3D视图拿给非光学专业的人看,对方可能只觉得“一堆线好酷”,并不能理解主镜、次镜、焦面之间的关系。但Unity里可以做出很自然的场景:用户用鼠标右键拖拽旋转视角,滚轮缩放,按住中键平移,双击次镜还能单独查看它的面形。这种操作习惯对现代用户来说几乎零学习成本。

更关键的其实是“参数改变—现象改变”的即时反馈。在VirtualLab里改一次参数,重新跑一次仿真,可能要等几分钟;而在Unity里,用户拖一个滑块,光斑纹理马上切换,光路模型同步更新。虽然这个响应背后靠的是预计算数据,但对演示者来说,呈现效果就是实时的。这就是Unity补位的最大价值。

3.2 三类数据导出:几何参数、PSF纹理和光线

我从VirtualLab里导出的数据有三类,每一类在Unity里的用法都不一样。

第一类是几何参数,包括主镜焦距、两镜间距、后截距、次镜口径、遮挡比等,我整理成一个JSON文件,Unity启动时读取。这个文件相当于VirtualLab和Unity之间的“契约”,所有模型的缩放、位置都由它驱动。

第二类是PSF强度数组。我归一化之后把不同离焦量对应的PSF存成PNG纹理,Unity用TextureArray管理。这里要强调,导出时不要把PSF直接存成彩色图,因为颜色映射的信息会丢失。最好存灰度强度图,颜色映射放到Unity的Shader里做,这样后续想换成热力图、伪彩色图都很方便。

第三类是光线数据。这个比较麻烦。VirtualLab可以导出每条光线的起点坐标和方向向量,但数量一大,Unity的LineRenderer就扛不住了。我实际测试下来,两千条光线同时显示,帧率还能维持在40左右;再往上加到五千条,渲染压力立刻变大,旋转视角时明显卡顿。所以我在Unity里只保留一小部分代表性光线,用于示意光路走向,不再追求物理上的精确数量。

3.3 场景搭建与交互脚本:让用户动手调参

Unity场景搭建本身不复杂。主镜用圆柱体和环形柱体拼出来,中间开孔用布尔运算挖掉;次镜用一个小圆柱;镜筒用半透明管状模型,方便看到内部光路;探测器用一个薄片放在主镜后方。反射镜面用高光材质,可以在URP或HDRP下调出比较亮的反射效果。

交互脚本的核心是建立一个TelescopeData类,把从JSON读到的参数和Unity场景里的对象绑定起来。比如“次镜位置”对应TelescopeData.SecondaryPosition,“遮挡比”对应TelescopeData.ObscurationRatio。界面上放几个Slider,用户拖动滑块时,脚本更新模型位置、缩放,同时根据参数值从预计算结果中选取对应的PSF纹理。

还有一点值得注意:如果你想让主镜和次镜的材质看起来像镜子,别只调颜色,要调光滑度和金属度。卡塞格林望远镜的反射镜在可见光波段反射率很高,粗糙度应该很低。用默认的Standard材质把Smoothness拉到0.95以上,金属度设为1,效果会好很多。

3.4 性能优化:预计算和分级加载

因为PSF是预计算好的,运行时的计算压力主要在模型渲染和纹理采样上。我的优化思路是“分级加载”:进入场景时先加载低分辨率PSF,保证界面流畅;当用户停止拖动滑块时,再切换高分辨率纹理。这个“拖拽时用低精度、松手后用高精度”的方案,在演示场景里尤其好用。

光线的渲染也要分级。默认只显示6到8条特征光线,表示主光路;用户可以点击一个“显示全部光线”的按钮,这时才把一千条光线显示出来。用这种渐进的显示方式,既能满足专业用户想看完整光路的需求,又不会让普通演示一开始就卡成幻灯片。

4. 实操中容易踩的坑与排查实录

这个项目里我反复遇到问题的地方,集中在四个方面。它们不复杂,但每一个都能让你白折腾半天。

4.1 探测器一张白纸:先检查法向和遮挡体

如果VirtualLab里探测器一片空白,我第一件事不是检查参数,而是打开三维光路视图,看光线到底打到哪去了。卡塞格林系统里,主镜和次镜的反射法向非常容易搞混。主镜把入射光反射向次镜,法向应该指向光源一侧;次镜把光反射回主镜方向,法向应该指向主镜一侧。什么时候看到光线往镜筒外乱飞,多半是某个反射面的法向反了。

另一个容易被忽视的问题是中心遮挡体。我一开始没加吸收屏,结果从光源来的平行光穿过主镜中心孔,直接在探测器上形成一个亮斑。这个亮斑并不是真正的焦面像,而是一种“漏光”。后来加上次镜等大的圆形遮挡体,问题就消失了。判断依据很简单:如果探测器中心出现一个特别亮且形状规则的小点,先怀疑是不是漏光了。

4.2 光斑大小对不上:单位换算和PSF尺度

Unity集成阶段最容易出的问题,是光斑尺寸和VirtualLab结果对不上。VirtualLab默认单位一般是毫米,Unity里的世界单位通常按米理解。如果没做转换,模拟一个直径0.5mm的PSF,在Unity里可能直接被当成0.5米,看起来大得离谱。

我的做法是:导出PSF时记录空间步长,比如一个像素对应0.01mm;在Unity里创建显示面片时,把面片尺寸设置为像素数量乘以空间步长,再除以1000换算成米。这一步不写进脚本,每次手动估一定会出错。最好在导入工具里做一个自动换算函数。

4.3 参数一致但MTF对不上:孔径和像素数

如果你对比VirtualLab仿真的MTF和理论MTF曲线,发现有明显差异,先检查两个因素。一是主镜中心开孔内径是否设得太大,内径太大会增加额外遮挡,降低低频MTF;二是探测器像素数是否足够,PSF欠采样会让MTF在高频区域严重失真。我的经验是,PSF网格至少128×128,最好256×256。采样率太低时,算出来的MTF会带明显的“截断”痕迹,看起来像系统有问题,其实是数值精度不够。

4.4 画面卡顿:减少光线数、用TextureArray

Unity卡顿,九成是因为光线数量太多。一个由一千条LineRenderer画出来的场景,每帧都要更新顶点,CPU压力不小。我的建议是:默认只显示9条特征光线,包括中心光线、主镜边缘光线、次镜边缘光线等,用不同的颜色区分;只有在需要讲解完整光路时,才临时加载更多光线,讲解完再隐藏。

PSF纹理方面,建议用TextureArray而不是几十张单独的Texture,因为TextureArray在Shader里用索引采样非常高效,切换也快。如果项目发布到移动端,还要限制PSF纹理不超过256×256,控制带宽和内存占用。

5. 从卡塞格林望远镜往外扩展的思路

这个项目做完后,我发现这套“光学仿真+实时交互”的框架可以扩展到很多方向。卡塞格林望远镜只是里面的第一个载体,但它把整个链路完整跑通了。

5.1 光学教学虚拟实验室的玩法

对高校或者培训机构的光学实验来说,实体望远镜很难让学生反复拆装,更别说在课堂上做参数扫描实验。但如果做成Unity虚拟实验室,学生可以在电脑上修改主镜口径、次镜曲率半径、遮挡比,实时观察PSF和MTF变化。还可以增加“考核模式”:系统给定一个目标像质,学生需要自己调节参数把它优化到接近衍射极限。这比做一道计算题有意思得多。

5.2 增加“装调误差”和“失调仿真”维度

卡塞格林望远镜的装配误差对像质影响很大。次镜如果在x/y方向平移0.1mm,或者绕某个轴倾斜0.1度,像质就会明显下降。我在VirtualLab里做过次镜失调扫描,导出不同失调量下的PSF,在Unity里做成“故障注入”模式。演示时让用户尝试通过观察光斑形状判断故障原因,这是模拟实训中很实用的功能。

5.3 更进一步的数字孪生架构

如果项目不只用于演示,而是要给实际产品做数字孪生,可以把VirtualLab的仿真能力封装成后台服务,Unity只做前端展示。用户在Unity里改参数,后台调用VirtualLab重新计算,再把新的PSF和波前数据推回来。这种架构对网络和计算性能要求更高,但能做真正的“实时物理计算”,而不是预计算结果查表。对工业级产品验证来说,这是值得投入的方向。

做完这个卡塞格林望远镜项目,我个人最大的体会是:VirtualLab和Unity不是替代关系,而是分工关系。光学计算必须相信VirtualLab,展示交互必须相信Unity,两者之间的数据契约一定要在项目一开始就定清楚,尤其是单位、纹理尺寸、参数命名规范。要不要加光线数据、PSF用什么分辨率、离焦量分多少档,这些问题越早决定,后面集成越省力。这套方法不只是卡塞格林望远镜能用,换到别的光学系统,思路是一样的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询