StarSky 星图渲染模式涉及一些 DRO 项目中已经存在的相机相关内容,但涉及范围不是“重写或替换 DRO 相机系统”,而是“在 DRO 现有相机体系上追加星图渲染能力”。
具体分为两类:
StarSky InfiniteDirection 模式与 DRO 现有相机系统有直接依赖。
它会枚举运行时所有可用的 CameraType.Game 相机。
它会给每个符合条件的相机挂载 CommandBuffer。
它会在开启窗口补偿时调用 CameraConfigLoader.TryGetCameraWindowStarSizeCompensation(...),读取 DRO 相机窗口的 RenderTexture 与 UI 显示尺寸。
因此它直接依赖 DRO 已有的相机窗口创建、窗口相机管理和 RenderTexture 显示结构。
StarSky WorldSphere 模式与 DRO 相机系统只有间接关系。
它把星点作为普通世界空间 Mesh 渲染,不通过 CameraConfigLoader 查找相机窗口。
它可以把星空球中心放到 Camera.main、当前相机目标、地球、太阳或场景对象中心。
因此它依赖 DRO 的场景中心/当前目标体系,但不直接依赖 DRO 的相机窗口列表。
Assets/StarSky/** 这个 StarSky 包主体本身是独立的。它的 StarSky.Runtime.asmdef 没有引用 DRO 业务程序集。真正把 StarSky 接入 DRO 相机和 UI 的,是 Assets/NoloSpace/Scripts/NoloVR/** 下的接入层脚本。
这些代码提供星表读取、星点生成、Shader 和独立 Demo,不直接依赖 DRO 相机窗口:
| 文件 | 作用 | 与 DRO 相机关系 |
|---|---|---|
Assets/StarSky/Runtime/StarSky.Runtime.asmdef | StarSky 运行时程序集定义。references 为空,说明运行时包不依赖 DRO 程序集。 | 无直接依赖 |
Assets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.cs | 读取 Gaia 星表,构建星点 Mesh,支持 WorldSphere 和 InfiniteDirection 两种投影。 | 只使用 Unity 基础渲染对象,不识别 DRO 相机窗口 |
Assets/StarSky/Runtime/Visualization/Shaders/StarSkyInfiniteDirectionBillboard.shader | 无限远方向星点 Shader,按当前相机矩阵把方向投影到屏幕。 | 使用 Unity 当前相机矩阵和屏幕参数,不知道 DRO 相机结构 |
Assets/StarSky/Runtime/Visualization/Shaders/StarSkyAdditiveStarBillboard.shader | 世界球面星点 Shader。 | 普通 MeshRenderer 渲染 |
Assets/StarSky/Runtime/Visualization/StarRenderCameraController.cs | StarSky Demo 用相机控制器。 | Demo/独立验证用,不接入 DRO 相机窗口 |
这些代码把 StarSky 接入 DRO 的天空盒 UI、场景渲染和相机窗口:
| 文件 | 作用 | 与相机系统关系 |
|---|---|---|
Assets/NoloSpace/Scripts/NoloVR/SkyboxAttributeController.cs | 在天空盒选择器中加入 StarSky InfiniteDirection 和 StarSky WorldSphere,选择时启用 StarSky。 | 入口层,不直接访问相机,但决定是否启用会访问相机的渲染模式 |
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs | DRO 中 StarSky 的总控;创建 VectorStarSky 节点,配置 GaiaSkySphereRenderer 和 StarSkyInfiniteDirectionRenderer。 | 间接依赖相机;InfiniteDirection 时配置逐相机渲染器,WorldSphere 时可用 Camera.main 作为中心 |
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs | InfiniteDirection 模式的逐相机 CommandBuffer 渲染器。 | 直接依赖所有活动 Game Camera,并可调用 CameraConfigLoader |
Assets/NoloSpace/Scripts/NoloVR/StarSkySettingsPanelController.cs | StarSky 控制面板,提供亮度、星点大小、窗口补偿、中心模式等 UI。 | 通过 VectorStarSkyManager.SetCameraWindowStarSizeCompensation(...) 开关相机窗口补偿 |
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs | DRO 原有相机窗口加载器,本次增加 TryGetCameraWindowStarSizeCompensation(...)。 | StarSky 使用它查询相机窗口与 RenderTexture 尺寸关系 |
Assets/NoloSpace/Prefabs/天空盒子UI预设.prefab | 天空盒 UI 预设,Selector 中显式加入两项 StarSky 模式。 | UI 入口配置 |
Assets/NoloSpace/Scripts/NoloVR/SettingsManager.cs | 生成天空盒设置 UI,并把场景 SkyboxRenderer 传入 SkyboxAttributeController。 | StarSky UI 入口的上游 |
StarSky 在 DRO 中不是场景里固定写死的单一对象,而是从设置面板的天空盒选项进入。
xSettingsManager.LoadSettings() -> 实例化 SkyboxInfoPrefab -> 获取 SkyboxAttributeController -> 注入场景里的 SkyboxRenderer
SkyboxAttributeController.Start() -> EnsureStarSkyOptions() -> EnsureStarSkyControls() -> ApplySelection(selector.selectedIndex)
选择 StarSky InfiniteDirection 或 StarSky WorldSphere -> VectorStarSkyManager.SetStarSkyModeEnabled(true, SkyboxRenderer, projectionMode) -> VectorStarSkyManager.Ensure(SkyboxRenderer) -> VectorStarSkyManager.SetActiveMode(true) -> VectorStarSkyManager.EnsureRenderer() -> 创建 VectorStarSky 节点 -> 挂载 GaiaSkySphereRenderer -> 挂载 StarSkyInfiniteDirectionRenderer关键代码位置:
Assets/NoloSpace/Scripts/NoloVR/SettingsManager.cs:44-60
创建天空盒设置 UI,并把 SkyboxRenderer 注入 SkyboxAttributeController。
Assets/NoloSpace/Scripts/NoloVR/SkyboxAttributeController.cs:44-84
确保 Selector 中有 StarSky InfiniteDirection 和 StarSky WorldSphere。
Assets/NoloSpace/Scripts/NoloVR/SkyboxAttributeController.cs:86-120
根据选择启用 StarSky 或恢复传统天空盒材质。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:95-132
确保 StarSky 管理器存在,并启用指定投影模式。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:405-425
创建 VectorStarSky、GaiaSkySphereRenderer 和 StarSkyInfiniteDirectionRenderer。
InfiniteDirection 是和 DRO 相机系统耦合最明确的部分。
StarSkyInfiniteDirectionRenderer 在运行时每帧同步相机列表:
xxxxxxxxxxStarSkyInfiniteDirectionRenderer.LateUpdate() -> SyncCameras() -> Camera.allCameras -> ShouldRenderCamera(camera) -> AddCamera(camera) -> camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, commandBuffer)相关代码:
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:84-114
LateUpdate() 中同步相机、重建或刷新 CommandBuffer。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:116-141
遍历 Camera.allCameras,增删相机对应的 buffer。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:143-156
只接受非空、启用、非正交、CameraType.Game 的相机。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:158-173
给相机添加名为 StarSky Infinite Direction 的 CommandBuffer。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:175-189
相机失效或不再满足条件时移除并释放 CommandBuffer。
这意味着:
主相机可以看到 StarSky。
CameraConfigLoader 动态创建的窗口相机也可以看到 StarSky,只要它们是启用的 Game Camera。
这不是只服务 Camera.main 的实现,而是面向多相机/窗口相机的实现。
StarSkyInfiniteDirectionRenderer 会根据相机视锥剔除不需要绘制的星点 Mesh 面:
xxxxxxxxxxPopulateBuffer(camera, state) -> ResolveDisplayPixelScale(camera) -> skyRenderer.CopyGeneratedMeshDrawData(meshes, meshFaceNormals) -> ShouldDrawFace(camera, faceNormal) -> commandBuffer.DrawMesh(...)相关代码:
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:231-265
清空并填充每台相机的 CommandBuffer。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:285-315
根据相机 transform.forward、fieldOfView、aspect 计算是否需要绘制某个方向面。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:317-329
当相机方向、FOV、宽高比或窗口补偿比例变化时,重建该相机的绘制命令。
所以相机的这些属性会影响 StarSky:
Camera.transform.forward
Camera.fieldOfView
Camera.aspect
Camera.targetTexture
Camera.cameraType
Camera.orthographic
Camera.isActiveAndEnabled
窗口补偿链路如下:
xxxxxxxxxxStarSkySettingsPanelController -> VectorStarSkyManager.SetCameraWindowStarSizeCompensation(enabled) -> StarSkyInfiniteDirectionRenderer.Configure(..., compensateCameraWindowStarSize, maxCompensation) -> ResolveDisplayPixelScale(camera) -> CameraConfigLoader.TryGetCameraWindowStarSizeCompensation(camera, maxCompensation, out scale) -> 遍历 CameraConfigLoader.loadedCameras.Values -> 匹配 CameraInstance.Camera == camera -> 读取 CameraInstance.RenderTexture -> 读取 CameraInstance.CameraWindow.RenderRT.rectTransform -> 计算 RenderTexture 像素尺寸 / UI 显示像素尺寸 -> 写入 Shader property `_DisplayPixelScale`关键代码:
Assets/NoloSpace/Scripts/NoloVR/StarSkySettingsPanelController.cs:824-849
更新“窗口补偿”按钮 UI 状态。
Assets/NoloSpace/Scripts/NoloVR/StarSkySettingsPanelController.cs:876-884
状态栏显示“窗口补偿开/关”。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:391-403
设置 compensateCameraWindowStarSize,并标记 InfiniteDirection renderer dirty。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:568-600
把补偿开关和最大补偿值传给 StarSkyInfiniteDirectionRenderer。
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs:267-283
只有 compensateCameraWindowStarSize == true 且 camera.targetTexture != null 时才查询补偿。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:348-396
通过相机实例、RenderTexture、相机窗口 RenderRT 和 Canvas scaleFactor 计算补偿比例。
Assets/StarSky/Runtime/Visualization/Shaders/StarSkyInfiniteDirectionBillboard.shader:74-80
Shader 使用 _DisplayPixelScale 调整星点屏幕半径。
这里直接涉及 DRO 已有相机系统中的对象:
| DRO 相机对象 | 被 StarSky 使用的字段/结构 | 用途 |
|---|---|---|
CameraConfigLoader.Instance | 单例和 loadedCameras 字典 | 找到当前 Unity Camera 对应的 DRO 相机窗口实例 |
CameraConfigLoader.CameraInstance.Camera | Unity Camera | 匹配当前正在绘制的相机 |
CameraConfigLoader.CameraInstance.RenderTexture | 渲染纹理宽高 | 作为相机真实输出像素尺寸 |
CameraWindow.RenderRT | UI RawImage 或同类显示控件 | 取得窗口中实际显示区域 |
RenderRT.rectTransform.rect.size | UI 显示尺寸 | 计算显示像素大小 |
Canvas.scaleFactor | UI 缩放 | 把 UI 尺寸换算到显示像素 |
Camera.targetTexture | RenderTexture 绑定 | 判断该相机是否是窗口输出相机 |
如果目标工程删除或改造了 CameraConfigLoader、CameraWindow.RenderRT 或窗口显示结构,InfiniteDirection 的窗口补偿功能就需要同步改写。否则可以关闭补偿,StarSky 仍可通过 CommandBuffer 渲染,只是窗口内星点大小可能不符合期望。
DRO 的窗口相机由 CameraConfigLoader 动态创建:
xxxxxxxxxxCameraConfigLoader.LoadCameras() -> LoadSingleCamera(config) -> CreateCameraWindow(config) -> new GameObject("Camera_xxx") -> AddComponent<Camera>() -> CreateRenderTexture(config) -> camera.targetTexture = renderTexture -> cameraWindow.RenderRT.texture = renderTexture -> 保存 CameraInstance关键代码:
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:152-193
从当前消息读取相机配置并加载相机。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:200-224
加载单个相机,并把实例放入 loadedCameras。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:573-766
创建窗口、Unity Camera、RenderTexture、ProFlare、CameraInstance。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:615-648
创建 Camera,设置 targetTexture、裁剪距离和 cullingMask。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:664-668
把 RenderTexture 赋给窗口的 RenderRT.texture。
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:745-761
保存 CameraInstance,并让 CameraWindow 反向持有该实例。
StarSky 不负责创建这些相机,只是在这些相机存在后为它们追加星图绘制命令。
WorldSphere 模式不是逐相机 CommandBuffer 渲染,而是普通 MeshRenderer 渲染。
相关代码:
Assets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.cs:287-303
生成星点 Mesh 子物体,并在 projectionMode == WorldSphere 时启用 MeshRenderer。
Assets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.cs:319-321
WorldSphere 会把星点顶点放到 direction * visualizationRadius。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:538-548
WorldSphere 下把根节点缩放为 visualizationRadius,InfiniteDirection 下缩放为 Vector3.one。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:550-566
只有 WorldSphere 时启用生成的 MeshRenderer。
WorldSphere 与相机相关的主要点是中心模式:
| CenterMode | 代码行为 | 与相机关系 |
|---|---|---|
MainCamera | 返回 Camera.main.transform.position | 直接使用主相机位置 |
CurrentCameraTarget | 返回 orbitVectorMath.cameraTarget.transform.position | 依赖 DRO 主相机目标体系 |
ScenarioObjects | 返回 CelestialBodyManager.Instance.ScenarioObjects.position | 跟随场景对象根 |
Earth | 从 CelestialBodyManager.instantiatedBodies 查找 earth | 不直接依赖相机 |
SunBarycenter | 从 CelestialBodyManager.instantiatedBodies 查找 sun | 不直接依赖相机 |
关键代码:
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:19-26
定义 CenterMode。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:175-180
WorldSphere 下每帧更新星空球位置到 GetRenderCenter()。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:715-760
按中心模式解析中心点,最后 fallback 到 Camera.main。
Assets/NoloSpace/Scripts/NoloVR/StarSkySettingsPanelController.cs:761-795
WorldSphere 下显示半径和中心模式控制,隐藏窗口补偿。
因此 WorldSphere 可以被 DRO 相机看到,但它不需要 CameraConfigLoader 的相机窗口表。它的风险点更多是世界坐标、层级、cullingMask 和中心跟随策略,而不是窗口补偿。
DRO 项目本来已有 SkyboxRenderer,它也会用 CommandBuffer 渲染天空盒。
StarSky 启用时,VectorStarSkyManager 会停用传统 SkyboxRenderer:
xxxxxxxxxxVectorStarSkyManager.SetActiveMode(true) -> legacySkyboxRenderer.enabled = false -> DisableLegacySkyboxCommandRenderers()退出 StarSky 时再恢复:
xxxxxxxxxxVectorStarSkyManager.SetActiveMode(false) -> RestoreLegacySkyboxCommandRenderers() -> infiniteDirectionRenderer.enabled = false -> starSphereRoot.SetActive(false) -> legacySkyboxRenderer.enabled = true关键代码:
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:200-235
启停 StarSky,并启停传统天空盒 renderer。
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs:602-643
查找并关闭/恢复所有 SkyboxRenderer。
这说明 StarSky 与已有天空盒渲染系统是互斥启用关系,避免两个天空背景同时通过 CommandBuffer 叠加。
xxxxxxxxxxStarSky.Runtime -> UnityEngine -> 不引用 DRO 业务代码
StarSky.Editor -> StarSky.Runtime -> UnityEditor
Assembly-CSharp / NoloVR 接入层 -> StarSky.Runtime -> DRO 现有 NoloVR 脚本 -> Evo.UI / TMPro / Unity UI说明:
StarSky 包主体可以独立存在。
DRO 接入层依赖 StarSky 包主体。
StarSky 包主体不反向依赖 NoloVR.CameraConfigLoader。
只有 NoloVR.StarSkyInfiniteDirectionRenderer 这个接入脚本依赖 CameraConfigLoader。
xxxxxxxxxx天空盒 UI 选择 StarSky -> VectorStarSkyManager 激活 -> GaiaSkySphereRenderer 生成星点 Mesh -> InfiniteDirection: StarSkyInfiniteDirectionRenderer 给每个 Game Camera 追加 CommandBuffer -> 可选: CameraConfigLoader 提供相机窗口补偿StarSky 不主动生成 DRO 相机,不修改 CameraConfigLoader 的加载流程,也不改变 CameraWindow 的生命周期。
答案是:涉及,但范围明确。
| 相机相关内容 | 是否涉及 | 说明 |
|---|---|---|
主相机 Camera.main | 是 | WorldSphere 中心可跟随主相机;InfiniteDirection 枚举所有 Game Camera 时也会覆盖主相机 |
| DRO 动态相机窗口 | 是 | CameraConfigLoader 创建的窗口相机会被 Camera.allCameras 捕获并挂 CommandBuffer |
CameraConfigLoader.loadedCameras | 是 | 仅在开启窗口星点大小补偿时使用 |
CameraWindow.RenderRT | 是 | 仅用于计算窗口显示尺寸补偿 |
RenderTexture | 是 | 判断窗口相机、计算输出像素与 UI 显示像素比例 |
CameraConfigLoader.LoadCameras() 流程 | 间接涉及 | StarSky 不调用它,但依赖其已创建的相机实例 |
CameraAttributeController | 否 | 搜索结果未发现 StarSky 直接调用它 |
CameraFrustumRenderer | 否 | 与 DRO 相机窗口自身功能有关,StarSky 不直接调用 |
ProFlareBatch / 光晕相机配置 | 否 | CameraConfigLoader 同时创建它,但 StarSky 没有直接依赖 |
OrbitCamera | 间接涉及 | WorldSphere 可跟随当前相机目标体系,但不直接引用 OrbitCamera 类型 |
SkyboxRenderer | 是 | StarSky 启用时会关闭传统天空盒 CommandBuffer renderer,退出时恢复 |
如果只迁移 Assets/StarSky/**,可以跑 StarSky Demo,但不会自动接入 DRO 天空盒 UI 和相机窗口。
如果要让 DRO 主界面能选择 StarSky,必须同时迁移或合并:
Assets/NoloSpace/Scripts/NoloVR/VectorStarSkyManager.cs
Assets/NoloSpace/Scripts/NoloVR/StarSkyInfiniteDirectionRenderer.cs
Assets/NoloSpace/Scripts/NoloVR/StarSkySettingsPanelController.cs
Assets/NoloSpace/Scripts/NoloVR/SkyboxAttributeController.cs 中 StarSky 相关逻辑
Assets/NoloSpace/Prefabs/天空盒子UI预设.prefab 中的两个 StarSky Selector 项
如果要让 DRO 相机窗口内星点大小稳定,还必须合并:
Assets/NoloSpace/Scripts/NoloVR/CameraConfigLoader.cs:348-396
也就是 TryGetCameraWindowStarSizeCompensation(...) 方法。
如果目标工程相机窗口结构不同,不能直接照搬窗口补偿方法。需要把以下逻辑改成目标工程自己的窗口结构:
如何从 Unity Camera 找到业务相机实例。
如何拿到该相机的 RenderTexture。
如何拿到窗口中显示这个 RenderTexture 的 UI 矩形。
如何换算 Canvas 缩放后的显示像素尺寸。
如果不需要窗口补偿,可以关闭 compensateCameraWindowStarSize。关闭后:
InfiniteDirection 仍会给窗口相机绘制星图。
但当 RenderTexture 分辨率和 UI 显示尺寸差异很大时,窗口里星点可能偏大或偏小。
如果目标工程相机不在 CameraType.Game,或使用正交相机,当前 StarSkyInfiniteDirectionRenderer.ShouldRenderCamera(...) 会跳过这些相机。
如果目标工程对相机 cullingMask 或 layer 有特殊限制,需要检查 VectorStarSkyManager.ApplyLayerToGeneratedChildren() 和 CameraConfigLoader 中窗口相机的 cullingMask。InfiniteDirection 通过 CommandBuffer 绘制,受材质和相机事件影响更大;WorldSphere 作为 MeshRenderer 更受 layer/cullingMask 影响。
StarSky 启用时会关闭已有 SkyboxRenderer,这是为了避免传统天空盒和 StarSky 同时绘制。若目标工程有多个自定义天空背景 renderer,需要确认它们是否都应该被 DisableLegacySkyboxCommandRenderers() 管理。
StarSky 的核心星表和 Mesh 生成代码不依赖 DRO 原有相机系统;DRO 接入层依赖 StarSky。
但在 DRO 的实际星图渲染模式中,StarSky InfiniteDirection 明确涉及并依赖 DRO 已有相机窗口系统:它逐相机添加 CommandBuffer,并通过 CameraConfigLoader 查询窗口相机的 RenderTexture 与 UI 显示尺寸,给星点屏幕大小做补偿。
StarSky WorldSphere 则更像普通场景物体渲染,只在中心跟随策略上间接使用 Camera.main 或 DRO 当前相机目标体系,不依赖 CameraConfigLoader 的窗口相机列表。