AcademySoftwareFoundation / AcademySoftwareFoundation/openvdb

Expected output of firstActive function in HDDA.h

Open
#1,500 0 comments 0 reactions 0 assignees View on GitHub
nanovdb
Dominant language
C++
Stars
3.4k
Forks
774
Avg merge
3d 9h
Merged PRs (30d)
34

Description

Hello,
I am building a small voxel grid by building a `nanovdb::Grid` with 1s in places where voxels are non-empty (as far as I understand bool or mask grids are not yet supported in nanovdb).
To render, I then trace rays from the camera against the grid using the `firstActive` function in `nanovdb/nanovdb/util/HDDA.h` to get the index of the first active voxel intersected.
```C++
template
inline __hostdev__ bool firstActive(RayT& ray, AccT& acc, Coord &ijk, float& t)
{
if (!ray.clip(acc.root().bbox()) || ray.t1() > 1e20) {// clip ray to bbox
return false;// missed or undefined bbox
}
static const float Delta = 1.0001f;// forward step-size along the ray to avoid getting stuck
t = ray.t0();// initiate time
ijk = RoundDown(ray.start()); // first voxel inside bbox
for (HDDA hdda(ray, acc.getDim(ijk, ray)); !acc.isActive(ijk); hdda.update(ray, acc.getDim(ijk, ray))) {
if (!hdda.step()) return false;// leap-frog HDDA and exit if ray bound is exceeded
t = hdda.time() + Delta;// update time
ijk = RoundDown( ray(t) );// update ijk
}
return true;
}
```
If I output the normalized color of that outputed voxel's index in 3d space I obtain the following:
![firstActive](https://user-images.githubusercontent.com/11017784/197164199-fe50430e-ca8c-4c46-8c46-153f442cf899.png)

I found this other variant of first active intersection in an older github repo:

```C++
template
inline __hostdev__ bool firstActiveVariant(RayT& iRay, AccT& acc, Coord &ijk, float& t)
{
using TreeT = nanovdb::NanoTree;

TreeMarcher marcher(acc);
if (marcher.init(iRay)) {
const TreeT::LeafNodeType *node = nullptr;
float t0 = 0, t1 = 0;

while (marcher.step(&node, t0, t1)) {
DDA dda;
dda.init(marcher.ray(), t0, t1);
do {
ijk = dda.voxel();
// CAVEAT:
// This is currently necessary becuse the voxel returned might not actually be innside the node!
// This is currently happening from time to time due to float precision issues,
// so we skip out of bounds voxels here...
auto localIjk = ijk - node->origin();
if (localIjk[0] < 0 || localIjk[1] < 0 || localIjk[2] < 0 || localIjk[0] >= 8 || localIjk[1] >= 8 || localIjk[2] >= 8)
continue;

const uint32_t offset = node->CoordToOffset(ijk);
if (node->isActive(offset)){
t = dda.time();
return true;
}
} while (dda.step());
}
}
return false;
}
```
This one gives me the expected result but seems to be quite expensive and has a CAVEAT note that doesn't seem very good either.
![firstActiveVariant](https://user-images.githubusercontent.com/11017784/197165303-8b54165a-6aaa-48f9-865d-efc33ef747a3.png)

The input to both functions is exactly the same, namely, the world_ray transformed into index space using the ray's `worldToIndexF` function and the device float grid accessor.

Is this a bug in the `firstActive` function or am I using it the wrong way?

Let me know if you need any more details.
Best,
Philippe

Contributor guide

Open the contributing guide

Research direction

Begin with nanovdb/nanovdb/util/HDDA.h and inspect firstActive alongside the older firstActiveVariant shown in the issue. Reproduce the differing voxel indices with the same world_ray transformed by worldToIndexF and the device float grid accessor; done means determining whether the discrepancy is a bug or incorrect use and recording the confirmed expected behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.