计算机图形学示例概览¶
本文档介绍 nblade 在计算机图形学中的应用示例。
示例列表¶
01_transformations.py - 几何变换¶
难度: ⭐⭐⭐ 高级
内容: - 反射变换 - 投影操作 - 旋转操作 - 缩放变换 - 组合变换 - 三角形变换示例 - 共形几何代数简介
运行:
预期输出:
============================================================
nblade 计算机图形学变换示例
============================================================
============================================================
第1节:反射
============================================================
反射是最基础的几何变换
公式: v' = -n·v·n (n 为单位法向量)
【向量反射】
原始向量 v = 1.000000e1 + 2.000000e2 + 3.000000e3
反射平面法向量 n = 1.000000e1 (yz 平面)
反射结果 v' = 1.000000e1 + -2.000000e2 + -3.000000e3
...
02_projection.py - 投影操作¶
难度: ⭐⭐⭐ 高级
内容: - 向量投影到另一个向量 - 子空间投影(投影到平面) - 拒绝分量(正交分量) - 实际应用:阴影计算
运行:
预期输出:
============================================================
nblade 投影操作示例
============================================================
============================================================
第一节:向量投影
============================================================
向量投影将一个向量分解到另一个向量的方向上
公式: proj_u(v) = (v·u / |u|²) · u
【基本向量投影】
向量 v = 3.000000*e1 + 4.000000*e2
投影方向 u = 1.000000*e1
投影结果 proj_u(v) = 3.000000*e1
注意:y 分量被移除,只剩下 x 分量
...
03_reflection.py - 反射操作¶
难度: ⭐⭐⭐ 高级
内容: - 向量反射(在超平面/向量法向) - 平面反射 - 多次反射的组合 = 旋转 - 实际应用:镜面反射模拟
运行:
预期输出:
============================================================
nblade 反射操作示例
============================================================
============================================================
第一节:向量反射(超平面反射)
============================================================
反射是最基本的几何变换,所有等距变换都可以由反射组合而成
在几何代数中,反射公式为: v' = -n·v·n
其中 n 是反射超平面的单位法向量
【基本反射】
原始向量 v = 1.000000*e1 + 2.000000*e2 + 3.000000*e3
反射面法向量 n = 1.000000*e1
反射结果 v' = -1.000000*e1 + 2.000000*e2 + 3.000000*e3
注意:x 分量被取反
...
核心概念¶
反射¶
反射是最基础的几何变换。其他变换都可以通过反射的组合得到。
公式: v' = -n v n
其中 n 是反射平面的单位法向量。
旋转¶
旋转使用转子实现。
公式: v' = R v R†
import math
# 创建转子
plane = e1 ^ e2 # xy 平面
rotor = alg.rotor(plane, math.pi / 4) # 45°
# 旋转
rotated = v.rotate_by(rotor)
投影¶
将向量投影到子空间。
公式: proj_B(v) = (v⌋B)⌋B⁻¹
v = alg.vector([1, 2, 3])
# 投影到 x 轴
proj = v.project_to(e1)
# 正交分量
reject = v.reject_from(e1)
# v = proj + reject
拒绝分量¶
拒绝分量是向量中与投影方向正交的部分。
公式: rej_B(v) = v - proj_B(v)
v = alg.vector([3.0, 4.0, 5.0])
direction = e1
proj = v.project_to(direction)
reject = v.reject_from(direction)
# proj 和 reject 正交
组合变换¶
多个变换通过几何积组合。
# 先旋转,再反射
result = v.rotate_by(rotor).reflect_in(n)
# 变换顺序很重要!
result2 = v.reflect_in(n).rotate_by(rotor) # 不同结果
与传统方法的对比¶
| 操作 | 传统方法 | 几何代数方法 |
|---|---|---|
| 旋转 | 3×3 矩阵 | 转子(4 个参数) |
| 反射 | 3×3 矩阵 | 向量乘法 |
| 组合 | 矩阵乘法 | 几何积 |
| 插值 | 欧拉角/四元数 | 转子 SLERP |
优势: - 参数更少(转子 vs 旋转矩阵) - 数值稳定性更好 - 避免万向节锁 - 统一的运算规则
共形几何代数(CGA)¶
共形几何代数 G(4,1,0) 扩展了 3D 欧几里得代数,可以表示:
- 点、线、平面
- 圆、球体
- 刚体运动(包括平移)
CGA 的优势¶
- 所有几何对象都是多向量
- 通过外积进行交集运算
- 平移和旋转统一为转子
- 公式简洁,避免特殊情况
实用技巧¶
批量变换点集¶
# 创建多个点
points = [e1, e2, e3, e1 + e2]
# 创建转子
rotor = alg.rotor(e1 ^ e2, math.pi / 4)
# 批量旋转
rotated_points = [p.rotate_by(rotor) for p in points]
从两点确定反射平面¶
# 两点确定一条直线,该直线的垂直平面可用作反射面
p1 = alg.vector([1, 0, 0])
p2 = alg.vector([0, 1, 0])
line = p2 - p1
# 反射平面法向量需要外部指定
确定点在平面的哪一侧¶
point = alg.vector([1, 2, 3])
plane_normal = e3 # xy 平面
# 点积的符号表示在哪一侧
side = (point | plane_normal).scalar_part()
if side > 0:
print("在平面的正侧")
elif side < 0:
print("在平面的负侧")
else:
print("在平面上")
阴影计算¶
# 正交投影到地面
ground_plane = e1 ^ e2 # xy 平面
shadow_point = point.project_to(ground_plane)
# 斜投影(考虑光源方向)
def oblique_projection(point, direction, plane_normal):
point_dot_n = (point | plane_normal).scalar_part()
dir_dot_n = (direction | plane_normal).scalar_part()
t = -point_dot_n / dir_dot_n
return point + direction.scale(t)
常见问题¶
Q: 转子与四元数有什么区别?¶
A: 四元数是几何代数的偶子代数。转子是更一般的概念,可以在任意维度中表示旋转。在 3D 中,它们是等价的。
Q: 如何实现平移?¶
A: 在标准几何代数中,平移通过向量加法实现。在共形几何代数中,平移也是转子,与旋转统一。
Q: 如何进行旋转插值?¶
A: 使用 SLERP(球面线性插值)对转子进行插值:
参考¶
- Geometric Algebra for Computer Science - Dorst, Fontijne, Mann
- GA Wiki - 共形几何代数