实验五:三维模型的观察、投影与交互式复合变换
学号:202412211401015 姓名:陈贤誉 日期:2026-11-09
1. 实验目标与实现
完成三种OBJ模型的归一化、四方向观察、正交/透视投影、鼠标键盘T/R/S和指定点旋转工作台。使用原生JavaScript、WebGL2及教师配套库;所有页面离线运行。
2. 主要原理
采用右手世界坐标、列向量,整体矩阵链为:
先把包围盒中心 移到原点,再按最长边 等比缩放:
矩阵从右向左作用。分别按轴缩放会改变长宽高比例,因此归一化只使用同一尺度。物体的世界坐标由 决定,与相机矩阵无关。
观察矩阵为 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:
其中d是当前模型中心的观察深度。鼠标Y向下为正,因此上方向项取负。滚轮只沿eye与target的连线调节距离,保留Model尺度。
E的绕点变换为:
固定点P满足 。移动标记使用 ,因此既能显示公转,也能核验轨道半径。主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。

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被明确拒绝,恢复有效参数后继续绘制。

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没有变化。


进一步数值控制:观察坐标中在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。

故障实验临时固定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、滚轮和键盘操作,截图记录交互后的状态。

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的局部坐标旋转,再平移回世界 |


补充验证:90°时按D,实际模型世界中心从(1,0,1)变为约(1.1,0,1),说明外层绕点变换未破坏世界轴平移。若关闭主OBJ联动,仅修改自身rx/ry,归一化中心仍停留在平移位置,体现自转与绕点旋转的差别。
综合操作链已自动执行:切换模型→本地导入→正/侧/斜视切换→两种投影及参数调整→绕点联动→键盘操作→PNG导出→完整重置。
8. 验证与边界
- 数值验收:10组通过,原始结果
evidence/numeric-results.json。 - 页面验收:真实Chromium离线加载A—E,未产生HTTP请求、JavaScript或Console错误;原始参数和结果
evidence/browser-results.json。 - 五个页面均点击截图按钮取得真实PNG下载,文件为
A_canvas.png至E_canvas.png;这些只包含画布,其他截图还包含状态栏。 - 测试脚本在
tests/,可重复运行;源文件中不含未实现的核心占位函数。 - 未替学生确认本人实测、真实姓名学号及外部双渠道提交。
- 仅实现简单OBJ、基础面色和绕世界Y轴的指定点旋转;不包含材质、纹理、动画或任意轴旋转。
9. 实验思考题
- N与M: N统一导入尺寸和中心,M描述场景中的运动;原始模型尺度合适时可省N,但切换任意模型不可靠。
- 相机与世界坐标: 世界坐标由MN确定,V只是把世界点转换到观察空间。
- eye/target/up: eye确定位置,target确定前向,up确定画面上方向;三者共同建立观察基。
- 顶部up: 常规Y向上与顶部观察方向共线,叉积为零,需换不平行的up。
- 正交远近等大: x/y映射与观察深度无关,相同方向、相同尺度的物体投影尺寸相同。
- FOV越大越小: 焦距因子cot(FOV/2)减小,投影坐标收缩。
- 存在但不可见: 点可能在相机后方、视锥外或裁剪面外,也可能被其他物体遮挡;不等于网格被删除。
- 模型旋转与相机环绕: 前者改M且eye不变,后者改V且世界位置不变;多个对象与固定参照会暴露二者差异。
- 矩阵顺序: 依次N归一化、M模型、V观察、P投影,然后裁剪、透视除法、视口及光栅化。
- 建议与画面矛盾: 固定无关变量,打印M/V/P、世界中心、aspect和clip坐标,构造单点或单位线段测试,再检查实际画面。
补充:相机靠近改变观察距离,可能影响物体之间的透视关系、遮挡和裁剪;Model放大改变物体世界尺寸,不会等价放大整个场景。Shift方向需结合观察基,才能在侧面、顶部仍沿屏幕右/上方向移动。