5个版本
0.1.4 | 2018年12月1日 |
---|---|
0.1.3 | 2018年11月24日 |
0.1.2 | 2018年11月20日 |
0.1.1 | 2018年11月17日 |
0.1.0 | 2018年11月17日 |
#107 在 数据格式
每月 27次下载
46KB
804 行
immense
一个使用简单可组合规则描述3D网格的库。
rule![
tf![
Tf::saturation(0.8),
Tf::hue(160.0),
Replicate::n(36, vec![Tf::rz(10.0), Tf::ty(0.1)]),
Replicate::n(36, vec![Tf::ry(10.0), Tf::tz(1.2), Tf::hue(3.4)]),
] => cube()
]
lib.rs
:
immense使用简单可组合规则描述3D结构,并以Wavefront对象文件的形式输出,您可以将其插入您选择的渲染器中。
演示
# use immense::*;
Rule::new().push(vec![
Replicate::n(1, vec![Tf::saturation(0.8), Tf::hue(160.0)]),
Replicate::n(36, vec![Tf::rz(10.0), Tf::ty(0.1)]),
Replicate::n(36, vec![Tf::ry(10.0), Tf::tz(1.2), Tf::hue(3.4)]),
],
cube(),
)
# ;
目录
简介
在immense中,您创建一个描述您结构的规则,该规则最终由网格组成。immense提供了一些内置网格,例如cube,您可以通过这些内置规则创建自己的规则,您将在下一节中看到。
构建您的规则后,您可以将其展开的网格导出为Wavefront对象文件,以便于您的下一步工作流程,无论是在Blender中渲染,用3D打印机打印,还是导入到您的游戏中!
组合规则
让我们从一个立方体开始。您可能想将网格写入文件,并在查看器中使用自动重载来查看它们。 Meshlab是一个出色的查看器(还有很多其他功能),可以在更改时重新加载您的网格。查看ExportConfig以了解您可以为渲染或打印工作流程设置的最佳选项。
use immense::*;
use std::fs::File;
let rule = cube();
let meshes = rule.generate();
let mut output_file = File::create("my_mesh.obj")?;
write_meshes(ExportConfig::default(), meshes, &mut output_file)?;
我们可以使用Tf::t*
函数系列来转换立方体,这些函数生成转换变换。我们将通过创建自己的规则并使用转换调用立方体规则来应用Tf::tx。
let rule = Rule::new().push(Tf::tx(3.0), cube());
我们可以使用Replicate来复制变换,它生成多个子规则的调用,每个调用都应用了相同的变换。
let rule = Rule::new().push(Replicate::n(3, Tf::ty(1.1)), cube());
请注意我们的翻译是1.1,而这是比我们的立方体长度多0.1。这不是巧合!所有内置网格长度都是1,这样您就可以使用这种方便的测量方法,即使在转换堆栈深处也是如此。
递归
您可以使用我们迄今为止介绍的API递归地生成规则,但这样做会将您的整个规则树一次性放入内存,这可能会成为一个问题。immense提供了一个特性,ToRule,因此您可以为它提供在需要时可以实例化规则的类型。
struct RecursiveTile {
depth_budget: usize,
}
impl ToRule for RecursiveTile {
fn to_rule(&self) -> Rule {
let rule = Rule::new()
.push(vec![Tf::t(0.25, 0.25, 0.0), Tf::s(0.4)], cube())
.push(vec![Tf::t(-0.25, -0.25, 0.0), Tf::s(0.4)], cube())
.push(vec![Tf::t(-0.25, 0.25, 0.0), Tf::s(0.4)], cube());
if self.depth_budget > 0 {
rule.push(
vec![Tf::t(0.25, -0.25, 0.0), Tf::s(0.4)],
RecursiveTile {
depth_budget: self.depth_budget - 1,
},
)
} else {
rule
}
}
}
let rule = RecursiveTile {
depth_budget: 3
}.to_rule();
随机性
使用ToRule来延迟规则构建,我们可以在每次我们的类型构建规则时采样一些随机值。
struct RandCube;
impl ToRule for RandCube {
fn to_rule(&self) -> Rule {
Rule::new().push(
*thread_rng()
.choose(&[Tf::tx(0.1),
Tf::tx(-0.1),
Tf::tx(0.2),
Tf::tx(-0.2)])
.unwrap(),
cube(),
)
}
}
let rule = Rule::new().push(Replicate::n(4, Tf::ty(1.0)),
RandCube {});
颜色
immense可以与您的网格一起导出一些颜色,通过将对象文件输出链接到一个mtl文件(材质库)。在export_colors中设置输出mtl文件,immense将写出颜色。
您可以使用Ogeon的[调色板][palette]指定颜色覆盖和HSV颜色空间中的变换。请参阅Tf::color、Tf::hue、Tf::saturation、Tf::value。
人体工程学宏
immense提供了两个使定义规则和变换序列变得更简单的宏,一旦您对其语义有了直观的理解。它们是rule!
和[tf!
],它们分别帮助组合规则和变换序列。
它们将上面的示例代码转换为
rule![
tf![
Tf::saturation(0.8),
Tf::hue(160.0),
Replicate::n(36, vec![Tf::rz(10.0), Tf::ty(0.1)]),
Replicate::n(36, vec![Tf::ry(10.0), Tf::tz(1.2), Tf::hue(3.4)]),
] => cube(),
]
自定义网格
您可以通过调用Mesh::from来创建自己的网格并将其作为规则使用,前提是您根据对象文件格式格式化您的网格。
网格可能很昂贵。immense代表您处理原始数据,但如果您引入自己的网格,您必须小心不要多次分配它们。一百万个球体引用是好的,但一百万个球体可能会杀死进程。
例如,sphere内置功能允许您创建一个可能昂贵的球体估计
let sphere: Rc<Mesh> = sphere(/*resolution=*/4);
let rule = Rule::new().push(Tf::s(2.0), sphere);
依赖项
~7.5MB
~150K SLoC