Flutter 伪 3D 绘制#02 | 地平面与透视

上一篇我们实现了三维空间点到二维平面的映射,并且绘制了坐标轴。本文将进一步完善三维空间的视觉表现,如下所示,构建一个地平面网格, 并且具有透视效果:


1. 地平面绘制

在数学的立体几何中,一些辅助线可以更好地帮我们理解三维空间。 这里准备在 X-Y 平面绘制一个网格,体现出地平线,这可以在视觉上让我们更具有归属感:

绘制网格非常简单,主要就是找到坐标,遍历收集线条绘制。如下代码中,遍历 6 次,收集横纵方向上各 6 条线:

dart 复制代码
void _drawGrid(Canvas canvas) {
  List<(Point3D, Point3D)> lines = [];
  for (double i = 0; i <= 5; i++) {
    lines.add((Point3D(i, 0, 0), Point3D(i, 5, 0)));
    lines.add((Point3D(0, i, 0), Point3D(5, i, 0)));
  }
  
  Paint paint = Paint() ..color = Colors.white..strokeWidth = 1;
  for (var line in lines) {
    Offset p0 = project(line.$1);
    Offset p1 = project(line.$2);
    canvas.drawLine(p0, p1, paint);
  }
}

然后可以修改一下遍历的个数,以及线的长度,就可以轻松实现一个 10*10 的网格:

dart 复制代码
List<(Point3D, Point3D)> lines = [];
for (double i = -5; i <= 5; i++) {
  lines.add((Point3D(i, -5, 0), Point3D(i, 5, 0)));
  lines.add((Point3D(-5, i, 0), Point3D(5, i, 0)));
}

2. 透视效果

仔细观察不难看出,目前的地平面每条线都是平行的,这对于近大远小的视觉感来说比较为何,特别是旋转角度后,这种绝对的平行会产生违和感:


那么该如何在当前的效果上施加 透视 的魔法呢?如下效果的对比可以看出,施加透视之后,感官上舒适了很多:

未透视 透视效果

透视效果本质上还是在三维点到二维点映射过程,根据视觉规律进行的转换。如下所示,两行代码即可在转换过程中施加透视效果:

dart 复制代码
// 3D点投影到2D平面
Offset project(Point3D p) {
  double scale = 32.0; // 缩放系数
  double angle = 30 / 180 * pi; // 30度弧度值(π/6)
  // 绕Z轴旋转
  final rx = p.x * cos(rotationZ) - p.y * sin(rotationZ);
  final ry = p.x * sin(rotationZ) + p.y * cos(rotationZ);
  // 等轴测投影
  final xProj = (rx - ry) * cos(angle);
  final yProj = (rx + ry) * sin(angle) - p.z;
  // 增加透视
  double d = 18.0;
  double radio = d / (d - yProj);
  return Offset(xProj * scale * radio, yProj * scale * radio);
}

当动态修改 d 的值,可以调整透视的效果,如下所示。至于为什么这样就可以实现透视,以及 d 的具体作用。不用着急,后续会一点点分析揭秘:


多绘制一些直线,可以更好地表现地平面和透视的效果。如下所示,在旋转过程中,外部延伸的线条可以联想成路面,越往远处路面线的长度越短,符合透视的规律:

dart 复制代码
List<(Point3D, Point3D)> lines = [];
for (double i = -32; i <= 32; i++) {
  lines.add((Point3D(i, -5, 0), Point3D(i, 5, 0)));
  lines.add((Point3D(-5, i, 0), Point3D(5, i, 0)));
}

尾声

本想这一篇介绍一下映射原理的,但是发现增加透视会有更好的感官体验,绘制地平面也可以更好地为之后的分析做铺垫。下一篇我将会详细分析一下投影的映射逻辑,敬请期待 ~

更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
每次的天空7 小时前
Android学习总结之算法篇四(字符串)
android·学习·算法
x-cmd8 小时前
[250331] Paozhu 发布 1.9.0:C++ Web 框架,比肩脚本语言 | DeaDBeeF 播放器发布 1.10.0
android·linux·开发语言·c++·web·音乐播放器·脚本语言
bst@微胖子9 小时前
Flutter项目之登录注册功能实现
开发语言·javascript·flutter
小墙程序员10 小时前
Flutter 教程(十一)多语言支持
flutter
tangweiguo0305198711 小时前
Android BottomNavigationView 完全自定义指南:图标、文字颜色与选中状态
android
遥不可及zzz12 小时前
Android 应用程序包的 adb 命令
android·adb
无知的前端13 小时前
Flutter 一文精通Isolate,使用场景以及示例
android·flutter·性能优化
_一条咸鱼_13 小时前
Android Compose 入门之字符串与本地化深入剖析(五十三)
android
yidahis13 小时前
Flutter 运行新建项目也报错?
flutter·trae
木马不在转13 小时前
Flutter-权限permission_handler插件配置
flutter