1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #if defined(NANOVDB_USE_OPENVDB)
5
6 #include <cmath>
7 #include <chrono>
8
9 #include <openvdb/openvdb.h>
10 #include <openvdb/math/Ray.h>
11 #include <openvdb/tools/LevelSetSphere.h>
12
13 #include <nanovdb/util/CudaDeviceBuffer.h>
14 #include <nanovdb/util/NanoToOpenVDB.h>
15
16 #include "common.h"
17
18 #if defined(NANOVDB_USE_CUDA)
19 using BufferT = nanovdb::CudaDeviceBuffer;
20 #else
21 using BufferT = nanovdb::HostBuffer;
22 #endif
23
runOpenVDB(nanovdb::GridHandle<BufferT> & handle,int numIterations,int width,int height,BufferT & imageBuffer)24 void runOpenVDB(nanovdb::GridHandle<BufferT>& handle, int numIterations, int width, int height, BufferT& imageBuffer)
25 {
26 using GridT = openvdb::FloatGrid;
27 using CoordT = openvdb::Coord;
28 using RealT = float;
29 using Vec3T = openvdb::math::Vec3<RealT>;
30 using RayT = openvdb::math::Ray<RealT>;
31
32 auto srcGrid = nanovdb::nanoToOpenVDB(handle);
33 std::cout << "Exporting to OpenVDB grid[" << srcGrid->getName() << "]...\n";
34
35 auto h_grid = (GridT*)srcGrid.get();
36
37 float* h_outImage = reinterpret_cast<float*>(imageBuffer.data());
38
39 auto indexBBox = h_grid->evalActiveVoxelBoundingBox();
40 auto gridXform = h_grid->transformPtr();
41 auto worldBBox = gridXform->indexToWorld(indexBBox);
42 float wBBoxDimZ = (float)worldBBox.extents()[2] * 2;
43 Vec3T wBBoxCenter = Vec3T(worldBBox.min() + worldBBox.extents() * 0.5f);
44
45 RayGenOp<Vec3T> rayGenOp(wBBoxDimZ, wBBoxCenter);
46 CompositeOp compositeOp;
47
48 openvdb::CoordBBox treeIndexBbox;
49 treeIndexBbox = h_grid->evalActiveVoxelBoundingBox();
50 std::cout << "Bounds: " << treeIndexBbox << std::endl;
51
52 auto renderOp = [width, height, rayGenOp, compositeOp, treeIndexBbox] __hostdev__(int start, int end, float* image, const GridT* grid) {
53 // get an accessor.
54 auto acc = grid->getAccessor();
55
56 for (int i = start; i < end; ++i) {
57 Vec3T rayEye;
58 Vec3T rayDir;
59 rayGenOp(i, width, height, rayEye, rayDir);
60 // generate ray.
61 RayT wRay(rayEye, rayDir);
62 // transform the ray to the grid's index-space.
63 RayT iRay = wRay.worldToIndex(*grid);
64 // clip to bounds.
65 if (iRay.clip(treeIndexBbox) == false) {
66 compositeOp(image, i, width, height, 0.0f, 0.0f);
67 return;
68 }
69 // integrate...
70 const float dt = 0.5f;
71 float transmittance = 1.0f;
72 for (float t = iRay.t0(); t < iRay.t1(); t += dt) {
73 float sigma = acc.getValue(CoordT::floor(iRay(t))) * 0.1f;
74 transmittance *= 1.0f - sigma * dt;
75 }
76 // write transmittance.
77 compositeOp(image, i, width, height, 0.0f, 1.0f - transmittance);
78 }
79 };
80
81 {
82 float durationAvg = 0;
83 for (int i = 0; i < numIterations; ++i) {
84 float duration = renderImage(false, renderOp, width, height, h_outImage, h_grid);
85 //std::cout << "Duration(OpenVDB-Host) = " << duration << " ms" << std::endl;
86 durationAvg += duration;
87 }
88 durationAvg /= numIterations;
89 std::cout << "Average Duration(OpenVDB-Host) = " << durationAvg << " ms" << std::endl;
90
91 saveImage("raytrace_fog_volume-openvdb-host.pfm", width, height, (float*)imageBuffer.data());
92 }
93 }
94
95 #endif
96