OpenVDB Cookbook 笔记

本文详细介绍了OpenVDB库中的关键概念,如创建和写入网格,元数据操作,网格遍历与插值,点数据处理,以及几何变换和组合。涵盖了从基本操作到高级功能,适合OpenVDB技术开发者深入学习。
摘要由CSDN通过智能技术生成

代码示例:

https://www.openvdb.org/documentation/doxygen/codeExamples.html#sHelloWorld

Hello World

初始化

创建网格

从网格获取访问器

创建坐标

修改坐标

访问器访问指定坐标

遍历网格

Creating and writing a grid

创建 openvdb::io::File 类型的对象,使用它来读写 vdb 文件

Populating a grid with values

第一步只创建表面周围的 SDF 值,也就是创建一个窄带

窄带的 SDF 值的区间取为 [-background_SDF, background_SDF]background_SDF 是正数,是背景的 SDF 值

按照一定的间隔,跳跃着遍历立方体 grid

遍历到的元素的 SDF 值如果在这个区间内,也就是在窄带内,那么就赋值,否则跳过

具体怎么计算遍历到的元素的 SDF 值,是 (x,y,z) - center 的长度减去球的半径

Reading and modifying a grid

遍历一个 openvdb::io::File 对象中的所有网络,根据网格名字查找到某一个网络

用网格基类存储查找到的网格。如果已知网格子类的类型,就可以直接 cast。

遍历 active 的 grid 元素,这些元素对应窄带 narrow band 元素

遍历 inactive 的 grid 元素,这些元素对应内部 interior 的元素

Stream I/O

写入(读取) string 流或者文件流

Handling metadata

元数据

Adding metadata

添加元数据

重复添加相同的名字相同类型的值,那么就是覆盖

如果是重复添加相同的名字不同类型的值,那么就报错

Retrieving metadata

已知元数据的数据类型,根据名字可以获取值

遍历元数据 map

可以获得元数据的 string 形式的类型名称,进而得知某个元数据的数据类型,进而进行类型转换

Removing metadata

删除不存在的元数据,不会报错,但是也没有效果

Iteration

Node Iterator

遍历树

Leaf Node Iterator

遍历叶子节点

遍历常量叶子节点

转换成引用或者指针

Value Iterator

遍历 active 的 grid 元素,这些元素对应窄带 narrow band 元素

遍历 inactive 的 grid 元素,这些元素对应内部 interior 的元素

Iterator Range

怎么使用 tbb 的 parallel_for 并行执行任务

首先要输入 openvdb 提供的迭代器

然后要自己创建一个重载了括号运算符的结构体

输入这个结构体作为任务

这个结构体的括号运算符的重载就是任务主体。它接受一个迭代器
,这个迭代器的范围是由 tbb 划分的,原始迭代范围的子区间

Interpolation of grid values

需要在分数坐标的值的时候,就需要在整数坐标的值之间插值

GridSampler 用于插值

GridTransformer 用于对所有值进行变换

Index-space samplers

在索引空间中插值

零阶插值 最近邻

一阶插值 线性

二阶插值 二次函数

通过树 grid.tree() 来访问是线程安全的,但是因为没有缓存,所以是次优的

最佳的是通过访问器,例如 grid.getConstAccessor()

因为访问器采用了缓存

也因此,访问器必须是一个线程一个访问器

Grid Sampler

GridSampler 可以在索引空间或者世界空间中插值

使用网格来构造 GridSamplerGridSampler 会自动获得索引空间到世界空间的变换

但是使用树或者访问器来构造 GridSampler,需要提供变换

用访问器构造 GridSampler 更快

Dual Grid Sampler

有些时候存在两个网格,一个源网格,一个目标网格

给定目标网格中的索引,需要从源网格得到相同索引位置的插值结果

所以提供了工具类 DualGridSampler

这个类还会检查两个网格的变换是不是一样的,如果不一样的话,这个任务就没有意义了

Transforming grids

Geometric transformation

有点不知道为什么,网格从一个变换转到另外一个变换是 源 transform 乘 目标 transform 的逆

Value transformation

openvdb::tools::foreach 可以遍历所有的值

openvdb::tools::transformValues 遍历源网格的值,同时把结果输出到一个目标网格

Combining grids

假设某个索引坐标,在两个网格中都对应同一个世界坐标,才能谈网格的组合

如果不是对应同一个世界坐标,那就是两个网格的变换不同,一般的方法是先将一个网格重新采样到另一个网格的索引空间

Level set CSG operations

Constructive solid geometry, CSG,构造立体几何

并集 交集 差集

Compositing operations

组合操作,取最大值,取最小值,加法,乘法

Generic combination

自定义操作符

使用 Tree::combine 来对两个树进行自定义操作符的操作

Tree::combineExtended 可以设置两个树的迭代元素的值和 active 状态

Tree::combine 将结果写到 A,B 留空;Tree::combine2 将结果写到第三个树

Generic programming

Calling Grid methods

这节演示了怎么泛型编程

processTypedGrid 这个函数用了一个叫作 dependent names 的特性,这个之前我还没见过,很酷

https://en.cppreference.com/w/cpp/language/dependent_name

The template disambiguator for dependent names
Similarly, in a template definition, a dependent name that is not a member of the current instantiation is not considered to be a template name unless the disambiguation keyword template is used or unless it was already established as a template name:

template<typename T>
struct S
{
    template<typename U>
    void foo() {}
};
 
template<typename T>
void bar()
{
    S<T> s;
    s.foo<T>();          // error: < parsed as less than operator
    s.template foo<T>(); // OK
}

之后的 PruneOp 类中也用到了这个特性

“Hello, World” for OpenVDB Points

对点集进行划分的工具类

对点集划分之后,可以计算体素大小

根据体素大小可以获得网格的变换

然后就可以创建点网格

根据字符串获得属性的这个,有点奇妙啊

const openvdb::points::AttributeArray& array =
            leafIter->constAttributeArray("P");

他用 “P” 来获得 position,这种缩写的规则,看上去就很容易搞混啊

从点网格获得属性的过程是,先获取叶子节点,然后得到 AttributeArray,然后得到 AttributeHandle

Converting Point Attributes

要对属性进行操作的时候,需要共通的 openvdb::tools::PointIndexGrid

创建 openvdb::points::PointDataGrid 的时候,还有把新的数组添加的网格的新字段的时候,都需要 openvdb::tools::PointIndexGrid

创建 openvdb::points::PointDataGrid 的时候,看上去是默认创建了一个名字为 “P” 的字段

然后之后如果要对点添加新字段的话,先注册类型

openvdb::points::TypedAttributeArray<float, Codec>::registerType();

然后再 openvdb::points::appendAttribute 添加字段到网格

现在网格有了字段,还是没有对应的数据

还要用 openvdb::points::populateAttribute 添加数据到对应字段

Random Point Generation

创建一个 openvdb::points::PointDataTree,可以拷贝别的网格的树结构来创建

要想使用 openvdb::points::PointDataTree 来创建 openvdb::points::PointDataGrid,还需要创建 openvdb::points::AttributeSet::Descriptor,然后 initializeAttributes 初始化 PointDataTree 的每一个叶节点

Point Iteration, Groups and Filtering

Point Iteration

迭代点网格的方法

两层循环,外层迭代树结构的所有叶子节点,内层对于每一个叶子节点,根据属性的名字构建 openvdb::points::AttributeArray,进而创建 openvdb::points::AttributeHandle。内层循环是对于叶子节点的每个索引,根据索引从 AttributeHandle 中 get 或 set 值

要使用 TBB 的并行,TBB 需要迭代器和回调函数,迭代器由 openvdb::tree::LeafManager 提供,回调函数就是自己创建结构体重载括号运算符

为了单线程调试 TBB,可以把输入的范围做成没有拆分的,对于 openvdb::tree::LeafManager 就是把 leafRange 的参数 grainsize 设置得很大,大于所有叶子节点的总数

Creating and Assigning Point Groups

树底下是节点,遍历叶子节点

叶子节点里面可以遍历 index

index 可以添加到 Group

添加到 Group 的 handle 需要从叶子节点这里获取

很神奇噢,属性句柄 AttributeHandle 和顶点组写入句柄 openvdb::points::GroupWriteHandle 都是从叶子节点这里得来的

Point Filtering using Groups

顶点组可以方便过滤迭代

如果已经创建好了一个顶点组

那么使用这个顶点组的名称就可以创建 openvdb::points::GroupFilter

在迭代某个叶子节点的 index 的时候,使用这个 filter,就可以自动遍历属于这个组的 index

for (auto indexIter = leafIter->beginIndexOn(filter); indexIter; ++indexIter) {

Point Filtering using Custom Filters

不用点组的话,可以自己创建一个结构体,提供 valid 函数,作为过滤器

Strided Point Attributes

步长表示每一个属性能有多少个值

Constant Stride Attributes

openvdb::points::appendAttribute 添加属性的时候,就把步长参数传进去了

Moving Points in Space

Advecting Points

使用一个均匀的场来平流点

Moving Points with a Custom Deformer

自定义平流方法

也是自定义一个结构体,提供特定函数的方法,形参是 vec3 和 index

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值