实验五:三维模型的观察、投影与交互式复合变换

学号:202412211401015 姓名:陈贤誉 日期:2026-11-09

1. 实验目标与实现

完成三种OBJ模型的归一化、四方向观察、正交/透视投影、鼠标键盘T/R/S和指定点旋转工作台。使用原生JavaScript、WebGL2及教师配套库;所有页面离线运行。

2. 主要原理

采用右手世界坐标、列向量,整体矩阵链为:

pclip=PVMNplocal. p_{clip}=PVMNp_{local}.

先把包围盒中心 c=(min+max)/2c=(min+max)/2 移到原点,再按最长边 LL 等比缩放:

N=S(2/L)T(−c),M=T Ry Rx S. N=S(2/L)T(-c),\qquad M=T\,R_y\,R_x\,S.

矩阵从右向左作用。分别按轴缩放会改变长宽高比例,因此归一化只使用同一尺度。物体的世界坐标由 MNMN 决定,与相机矩阵无关。

观察矩阵为 lookAt(eye,target,up)。令 forward=normalize(target-eye),right=normalize(forward×upHint),up=right×forward。观察方向接近竖直时选用Z方向提示向量,避免与forward共线。

正交体积取高度h、宽度h·aspect;透视使用以弧度表示的FOV。透视除法使屏幕尺寸与观察深度的绝对值成反比,正交投影不含这项深度缩放。near/far决定裁剪范围,不会删除网格。

Shift平移使用当前观察平面上的世界高度h_world及CSS画布高度H:

Δt=hworldH(Δx right−Δy up),hworld={h,正交,2dtan⁡(FOV/2),透视. \Delta t=\frac{h_{world}}{H}(\Delta x\,right-\Delta y\,up), \quad h_{world}=\begin{cases}h,&正交,\\2d\tan(FOV/2),&透视.\end{cases}

其中d是当前模型中心的观察深度。鼠标Y向下为正,因此上方向项取负。滚轮只沿eye与target的连线调节距离,保留Model尺度。

E的绕点变换为:

O=T(P)Ry(θ)T(−P),ME=O T Ry Rx S. O=T(P)R_y(\theta)T(-P),\qquad M_{E}=O\,T\,R_y\,R_x\,S.

固定点P满足 OP=POP=P。移动标记使用 O T(q) SO\,T(q)\,S,因此既能显示公转,也能核验轨道半径。主OBJ联动后,键盘的世界位移先乘外层旋转的逆,保证键盘仍沿世界坐标轴移动。

3. Task A:模型导入与归一化

本地文件 顶点 三角面 原始包围盒中心 最长边 归一化结果
sphere.obj 551 1008 (0,0,0) 2 中心(0,0,0),最长边2
teapot.obj 858 1512 (-0.010165,0.095,0) 3.56033 中心约(0,0,0),最长边约2
bunny.obj 1580 2728 (0.03,0.42,-0.015125) 2.66 中心约(0,0,0),最长边约2

指导书例:min=(-2,-1,-1)、max=(4,3,1),算得c=(1,1,0)、L=6、s=1/3。Float32实测尺度0.333333343,中心经过N后为(0,0,0)。

自动化依次切换三种模型,再通过真实文件选择框导入bunny.obj;导入坏OBJ后显示错误并保留原模型,随后可以继续切换。负索引四边面被拆成两个三角面。测试数据见 evidence/numeric-results.json 和 browser-results.json。

A:本地兔子OBJ导入

4. Task B:四方向相机

预设 eye target 特殊处理 模型世界中心
正面 (0,0,8) (0,0,0) upHint=(0,1,0) 约(0,0,0)
侧面 (8,0,0) (0,0,0) 同上 约(0,0,0)
顶部 (0,8,0) (0,0,0) upHint=(0,0,-1) 约(0,0,0)
斜上方 (6,4,7) (0,0,0) upHint=(0,1,0) 约(0,0,0)

四个View均有限且可逆,eye经View变到观察原点。正面→侧面→正面后View和Model逐项相等;世界中心不随相机变化。eye=target被明确拒绝,恢复有效参数后继续绘制。

B:顶部视图不退化

5. Task C:投影、FOV与裁剪

两张投影对照图均使用茶壶、相同N/M、eye=(0,0,8)、target=(0,0,0)、near=0.1、far=100、aspect=1.6。透视FOV=50°,正交高度=5.5。左立方体中心(-1.8,-0.75,0),右立方体中心(1.8,-0.75,-3),两者世界边长均0.78。

预测:正交下二者大小基本相同;透视下近者较大。实测画面符合预测,并逐项比较确认M/V没有变化。

C:透视近大远小

C:正交等尺寸对照

进一步数值控制:观察坐标中在z=-4和z=-8处放相同单位竖直线段,透视投影高度比为2,正交为1。z=-4时,FOV从50°改为80°,投影高度从0.536127降到0.297938。

两种投影均把观察坐标z=-near映射到NDC的-1,把z=-far映射到+1。near=0或far≤near出现错误提示;near推进到8时,网格部分被裁剪,模型三角面数仍为1512。

C:near=8时的裁剪

故障实验临时固定aspect=1,实际画布aspect=1.6,球体横纵屏幕单位比例变为1.6;恢复后为0.999999956。故障与恢复截图为 C_fault_aspect.png / C_fixed_aspect.png。测试结束已恢复正常函数。

6. Task D:鼠标与键盘

自动验证 操作和参数 结果
世界平移 初始按D tx=0.1,eye不变
普通拖动 实际拖40、20像素 ry=20°、rx=10°,平移不变
侧面Shift平移 正交高度5、画布高500;dx=100、dy=-50 世界位移(0,0.5,-1)
顶部Shift平移 同样参数 世界位移(1,0,-0.5)
滚轮dolly 初始距离8,deltaY=-120 距离7.095363,scale=1
缩放 按+再按- 1→1.1→1;下界0.15
复位 点击重置 所有M/V/P及E扩展参数等于默认状态
输入隔离 输入框获得焦点后按场景键 不移动场景模型

数值测试覆盖全部A/D、R/F、W/S、Q/E及+/-。浏览器另用真实鼠标、Shift、滚轮和键盘操作,截图记录交互后的状态。

D:实际交互后的状态

7. Task E:自主观察与两组记录

观察问题:自转与绕指定点旋转时,模型世界中心是否改变?

采用“可编辑指定点旋转”方案:输入P的三维坐标,显示固定点、运动标记和连杆;勾选主OBJ联动后,将相同的O作用于主OBJ。与双画布方案相比,此方案复用已有绘图,能直接核验非交换矩阵乘法。方案由AI辅助实现,本人最终确认见ai-log。

保持模型初始中心q=(0,0,0)、P=(1,0,0)、标记初始位置q_marker=(2.25,0,0)、半径1.25;使用导入的bunny.obj、eye=(6,4,7)、target=(0,0,0)、透视FOV=45°、near/far=0.1/100。

组别 预测 操作 自动实测 解释
1:θ=0° 模型中心仍为原点,标记在(2.25,0,0) 输入P,开启主OBJ联动,角度0° 模型中心约(0,0,0);P固定 Ry为单位矩阵,T(P)与T(-P)抵消
2:θ=90° 模型中心(1,0,1),标记(1,0,-1.25) 其余参数不变,仅角度改90° 与预测一致;标记距P仍为1.25 先平移到P的局部坐标旋转,再平移回世界

E:角度0°

E:角度90°

补充验证:90°时按D,实际模型世界中心从(1,0,1)变为约(1.1,0,1),说明外层绕点变换未破坏世界轴平移。若关闭主OBJ联动,仅修改自身rx/ry,归一化中心仍停留在平移位置,体现自转与绕点旋转的差别。

综合操作链已自动执行:切换模型→本地导入→正/侧/斜视切换→两种投影及参数调整→绕点联动→键盘操作→PNG导出→完整重置。

8. 验证与边界

9. 实验思考题

  1. N与M: N统一导入尺寸和中心,M描述场景中的运动;原始模型尺度合适时可省N,但切换任意模型不可靠。
  2. 相机与世界坐标: 世界坐标由MN确定,V只是把世界点转换到观察空间。
  3. eye/target/up: eye确定位置,target确定前向,up确定画面上方向;三者共同建立观察基。
  4. 顶部up: 常规Y向上与顶部观察方向共线,叉积为零,需换不平行的up。
  5. 正交远近等大: x/y映射与观察深度无关,相同方向、相同尺度的物体投影尺寸相同。
  6. FOV越大越小: 焦距因子cot(FOV/2)减小,投影坐标收缩。
  7. 存在但不可见: 点可能在相机后方、视锥外或裁剪面外,也可能被其他物体遮挡;不等于网格被删除。
  8. 模型旋转与相机环绕: 前者改M且eye不变,后者改V且世界位置不变;多个对象与固定参照会暴露二者差异。
  9. 矩阵顺序: 依次N归一化、M模型、V观察、P投影,然后裁剪、透视除法、视口及光栅化。
  10. 建议与画面矛盾: 固定无关变量,打印M/V/P、世界中心、aspect和clip坐标,构造单点或单位线段测试,再检查实际画面。

补充:相机靠近改变观察距离,可能影响物体之间的透视关系、遮挡和裁剪;Model放大改变物体世界尺寸,不会等价放大整个场景。Shift方向需结合观察基,才能在侧面、顶部仍沿屏幕右/上方向移动。