#tf #mesh #rule #composable #3d #structures #replicate

immense

一个用于使用简单可组合规则构建3D结构的库

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次下载

Apache-2.0

46KB
804

immense

crates.io

一个使用简单可组合规则描述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(),
)
 # ;

目录

  1. 简介
  2. 组合规则
    1. 递归
    2. 随机性
  3. 颜色
  4. 人体工程学宏
  5. 自定义网格

简介

在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::colorTf::hueTf::saturationTf::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