学习进度
0/9 已勾只保存在这台浏览器;勾满 9 项即视为本题完成。
先把题目说成人话
把游戏窗口从横屏转成竖屏时,圆形招牌不该被拉成椭圆;为了省性能只把内部画布的像素变少时,相机里能看见的范围也不该悄悄变窄。两种操作都碰到了“屏幕尺寸”,实际职责却完全不同。现实要解决的是先让三维场景形成正确构图,再把构图落到一块具体像素区域,最后才决定这块区域用多少像素来画。
把相机可见空间压到一张标准幕布的数学规则叫投影矩阵(Projection Matrix),幕布宽高关系叫宽高比(aspect)。投影后等待裁剪的位置叫裁剪坐标(clip space),除以第四分量后得到标准设备坐标(NDC);把标准坐标铺到像素矩形叫视口变换(Viewport Transform)。只调整内部像素密度的比例叫渲染比例(Render Scale)。
这是虚构教学故事,不是个人项目经历。
场景:先让问题变得看得见
想象投影仪先把空间中的圆投到一张标准幕布,再把整张幕布铺进最终屏幕。先观察横向幕布与纵向幕布中的圆是否仍为圆,再保持幕布形状不变,只把上面的方格画得稀一些。最后放入一近一远两个物体,用它们检查构图与深度关系有没有被错误混在一起。
(右脑)画面:投影仪先在半空中张开一个能看见的锥形范围,把锥里的三维物体压到一张没有像素格的标准幕布。幕布本身的长宽决定圆会不会变形,也决定横向能看见多少内容。随后工人把整张幕布贴到房间里的一块矩形墙面,墙面只负责它最终占据哪片区域。最后才在墙面上铺方格:方格变少会让边缘粗糙,却不该改变幕布里的构图。近处与远处物体的深度刻度也在第一步形成,不能指望最后铺方格时补救。
(左脑)对表:本题对象是视图空间位置、投影矩阵 P、裁剪坐标、NDC、viewport 矩形和内部 Render Target。横屏投影配竖屏 viewport 导致圆变椭圆、同 aspect 下 0.75 scale 不改构图是观察事实;“viewport 会自动修正错误 aspect”是假设。视图位置使用场景长度单位;clip 分量是投影后的齐次量,不能直接当世界距离或像素,只有透视除法后的 NDC 无长度单位;viewport 的 x0、y0、width、height 和目标尺寸以像素计。矩阵手性、NDC 深度范围、Y 翻转、near/far 与 reversed-Z 是平台前提。投影仪类比建立空间链,不等于证明所有 API 采用同一 NDC 或深度约定。
小明:先形成一个完整猜测
小明把窗口从横屏改成竖屏,只调整 viewport 宽高,投影矩阵仍保留 16:9 aspect。圆被拉成椭圆。这个结果说明:viewport 只负责落到哪块像素区域,无法补救错误的投影宽高比。
小红:把猜测放回现实检查
小红先保持 16:9,只把内部 Render Scale 从 1.0 改为 0.75:例如 1920×1080 变成 1440×810,aspect 仍是 16:9,所以投影和构图不变,只是采样分辨率降低。随后恢复 Render Scale,再把显示方向改成 9:16;此时需要用新 aspect 重建透视投影,或按项目构图策略调整 FOV。
从视图空间到像素的链是:
p_clip = P · p_view
p_ndc = p_clip.xyz / p_clip.w
p_pixel = viewport(p_ndc)
若 NDC 的 x、y 范围为 [-1,1],像素 x 可写成 x0 + (x_ndc+1)·width/2;y 是否翻转取决于图形 API 与 Render Target 约定,Unity 会处理平台差异,手写后处理时仍需核对。
我:用检查结果修正模型
我把三个职责拆开:屏幕形状或相机矩形改变时更新 aspect 与基础投影;viewport 决定最终像素矩形;动态分辨率更新内部目标尺寸、屏幕参数、TAA jitter 与依赖分辨率的后处理资源。在 aspect 不变时,未抖动的基础相机投影和构图不变;但 TAA 通常把随像素尺寸计算的偏移写进每帧实际使用的 jittered projection,因此抖动后的矩阵仍会更新。UI 若在独立原生分辨率目标上渲染,也不能跟着内部 3D Render Scale 一起缩。
深度同样属于投影约定:标准透视深度是非线性的,精度集中在 near 附近、远处更稀;near 设得过小会浪费大量可用精度并加重远处 z-fighting。Reversed-Z 能改善分布,但仍要配合 API、深度格式和裁剪约定验证。最终应在 Unity 的横竖屏、动态分辨率、后处理与目标平台上检查,而不是从单一分辨率外推。
(右脑)画面修正:小明从横屏切到竖屏只改 viewport,圆立刻被拉成椭圆,证明像素矩形不能补救错误的投影 aspect;小红保持 16:9,只把 1920×1080 降到 1440×810,构图和圆形比例不变,随后切到 9:16 并重建投影,圆才恢复。模型因此拆成三份职责:基础投影负责标准幕布的几何,viewport 负责像素落点,动态分辨率重建像素相关目标、TAA jitter 和后处理资源;只有 aspect 或构图策略改变时才改变基础投影,而每帧抖动后的投影仍可随像素偏移更新。
(左脑)严格对表:按列向量约定先定义未抖动基础投影 P_base;若启用 TAA,再由当前目标像素尺寸生成 jitter 并得到本帧 P_jittered。随后用本帧实际采用的 P_frame 计算 p_clip=P_frame·p_view、p_ndc=p_clip.xyz/p_clip.w,再由 x_pixel=x0+(x_ndc+1)width/2 映射 x;y 和 depth 使用当前 Unity/API 约定。显示矩形 aspect 改变时以新 aspect 重建基础透视或正交投影,并明确固定垂直/水平 FOV 的构图策略;仅 Render Scale 从 s 变为 s′ 且 aspect 不变时,基础构图不变,但要更新内部目标像素尺寸、Screen 参数、TAA jitter、jittered projection 与分辨率相关后处理资源,独立原生 UI 目标也不随之缩放。验收横/竖屏圆形比例、已知点像素落点、near/far 深度、0.75 scale 构图不变及目标平台 Y/depth 约定。
老师解惑
- 透视投影:通常由垂直/水平 FOV、aspect、near、far 控制;固定垂直 FOV 时,矩阵的 x 尺度常含
1/aspect。 - 正交投影:没有近大远小,由 orthographic size、aspect 与 near/far 确定可见盒子。
- NDC 与视口:NDC 是与像素无关的标准空间;viewport 才把它映射到具体像素矩形。
- 动态分辨率:改变的是内部像素预算及其相关资源;同一 aspect 下不必改变投影。
- 深度精度:标准透视中近处更密、远处更疏;把 near 无谓推得太近通常会恶化远处精度。
工具分工
- projection-dynamic-resolution Lab:观察 view、clip、NDC 与 pixel 四个空间。
- Unity Camera / URP-HDRP Render Scale:分别控制投影参数与内部渲染尺寸。
- Frame Debugger:确认实际 Render Target、viewport 和各 Pass 分辨率。
- 矩阵/Gizmo 调试:用已知点核对投影、裁剪和像素落点。
记忆钩子
投影决定三维怎样压到标准幕布,视口决定幕布贴到哪块像素;Render Scale 只换幕布的像素密度。
这是教学场景,不是目标项目的真实捕获或个人经历。
下一步:验证这条因果
跟着同一个点走完整条空间链,再看像素预算怎样变化。
教学边界:它只验证这一条画面因果,不替代完整答案、项目经历或目标设备数据。