rskynet 是用 Rust 语言编写的小程序,虽然它的名字叫天网(Skynet),但它的确是一个小程序,代码不足千行,以后也不会有更多的代码。之所以写这个程序,一是为了熟悉 Rust 语言,二是为了便于可视化我的一些三维数据。rskynet 的前身是一份用 Python 3 写的脚本,名字叫 hamal [1]。二者功能基本相同,但 rskynet 在选择三维场景的观察方位更为容易,因为它实现了当初我的一个构想 [2],即在场景的包围球上,以经纬度的方式构造观察方位。

源码的获取和编译

$ git clone https://gitee.com/garfileo/rskynet.git
$ cd rskynet
$ rustc -O rskynet.rs

用法

在 rskynet/data 目录,我提供了 5 份三维数据文件作为示例,其类型分别是点集(points.asc)、矢量集(vectors.asc)、线段集(paths.asc)、轴向盒集(boxes.asc),曲面网格(mesh.off),要实现它们的可视化,只需

# 渲染点集
$ rskynet --points points.asc
$ povray +A +P points.pov

# 渲染矢量集
$ rskynet --vectors vectors.asc
$ povray +A +P vectors.pov

# 渲染路径集
$ rskynet --paths paths.asc
$ povray +A +P paths.pov

# 渲染轴向盒集
$ rskynet --boxes boxes.asc
$ povray +A +P boxes.pov

# 曲面网格
$ rskynet --mesh mesh.asc
$ povray +A +P mesh.pov

rskynet 输出了什么?

以点集为例,将点集文件 foo.asc 输入 rskynet,亦即

$ rskynet --points foo.asc

rskynet 可在当前目录输出以下文件:

.
├── foo.inc
├── foo.ini
├── foo_object.inc
├── foo.pov
└── foo_view.inc

其中,foo.pov 用于汇总其他文件内容,形成完整的三维场景。

上述示例生成的 foo.pov 内容如下:

#version 3.7;
#include "colors.inc"
global_settings {assumed_gamma 1.0}

// 相机参数(可根据需要,自行修改)
#declare sky_u = 0;
#declare sky_v = 0;
#declare theta = 0;
#declare odc = 3; // Object distance coefficient.

// 系统参数(不建议自行修改)
#declare bs_center = <-0.278, 4.010, -2.365>; // 包围球中心
#declare bs_r = 156.802; // 包围球半径
#declare sky_r = odc * bs_r; // 天球半径

// 点、矢量、线段的尺寸参数
#declare point_size = 0.0025 * sky_r;
#declare line_width = 0.75 * point_size;
#declare arrow_size = point_size;

#include "foo_view.inc"
#include "foo_object.inc"

即使对 POV Ray 场景语言不熟悉也无妨,只需知道以下参数决定着三维场景的观察方位:

// 相机参数(可根据需要,自行修改)
#declare sky_u = 0;
#declare sky_v = 0;
#declare theta = 0;
#declare odc = 3; // Object distance coefficient.

其中,sky_usky_v 表示场景包围球的经度和纬度,其值若为正数分别表示东经和北纬,负数表示西经和南纬。theta 表示相机倾角,正数向右倾斜,负数表示向左倾斜。odc 是决定了场景包围球的大小,其值为 1 时,场景包围球近似为场景中所有三维数据的包围球,可以通过 odc 控制场景的放大和缩小。

三维观察

下图是基于默认的相机参数的渲染结果:

倘若将相机的经度参数修改为

#declare sky_u = 90;

则渲染结果变为:

将相机倾斜角度参数修改为

#declare theta = -90;

渲染结果变为

倘若将 sky_utheta 固定下来,不断修改 sky_v 的值,相当于在东经 90 度的经线上的各个维度查看图形。

倘若将 odc 的值缩小,可以观察到三维数据的局部,为了近距离看到点数据,也可以将 point_size 的值增大,例如:

#declare odc = 0.3;
... ... ...
#declare point_size = 0.01 * sky_r;

可得以下结果:

在通过经纬度和相机倾角构造观察方位时,务必记住,默认的初始方位是经纬皆为 0,且相机倾斜角度为零,此时相当于相机在赤道的经纬度为 0 的位置,头朝正北,向下俯瞰。倘若将相机移动到其他经纬坐标时,其顶端朝向与经线相切且指向北方,此时需要设身处地思考相机的倾角如何调整以获得符合需要的观察方位。

结语

若觉得 rskynet 有些用处,最好学一些 POV Ray 的基本知识,相信我,没那么难,浅尝辙止亦可。

Rust 不好用,特别是泛型,束手束脚,似乎是希望大家写代码时最好别用泛型……相形之下,我还是喜欢 C,感觉自己没救了。

补遗

rskynet 里隐含了一个很小的花活,在渲染点集时,使用了 POV Ray 提供的一个模拟锈迹的纹理,其名为「Rust」。碰巧 rskynet 是用 Rust 语言写的,因此该纹理的名字颇为应景。

在 rskynet 源码目录的子目录 data 内,有 mesh.off 文件,包含了曲面网格数据。使用 rskynet 处理该数据,即

$ rskynet --mesh mesh.off

在生成的 mesh_object.inc 文件里,有以下代码:

#include "textures.inc"
#include "mesh_mesh.inc"
object {
  mesh_data
  texture {pigment {color Gray50}}
}

#include "mesh_vertices.inc"
object {
  mesh_vertices_data
  texture {Rust scale 0.3 * sky_r}
}

//#include "mesh_edges.inc"
//object {
//  mesh_edges_data
//  texture {pigment {color Gray}}
//}

可以看到,曲面网格顶点集合的纹理是 texture {Rust scale 0.3 * sky_r}

本想将 Rust 纹理用于曲面渲染,尝试之后,发现会导致曲面细节不容易分辨,而且有时会令渲染结果观感颇为诡异,例如

这种渲染效果让我一度想换成其他纹理,只是忽然想到,若将该纹理施于点集,点集的离散性应当有助于瓦解这种观感的诡异性,试验后发现的确如此,如下图所示

[1] https://segmentfault.com/a/11...
[2] https://segmentfault.com/a/11...


garfileo
6k 声望1.9k 粉丝

这里可能不会再更新了。