1 // Copyright 2020-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include <random>
5 #include "../../external/catch.hpp"
6 #include "gradient_utility.h"
7 #include "openvkl_testing.h"
8 #include "rkcommon/utility/multidim_index_sequence.h"
9 #include "rkcommon/utility/random.h"
10 
11 using namespace rkcommon;
12 using namespace openvkl::testing;
13 
14 // these tests are only exact for procedural volume fields that vary linearly
15 // with time!
gradients_on_vertices_vs_procedural_values_motion_blur(std::shared_ptr<TestingStructuredVolumeMulti> v,vec3i step=vec3i (1))16 inline void gradients_on_vertices_vs_procedural_values_motion_blur(
17     std::shared_ptr<TestingStructuredVolumeMulti> v, vec3i step = vec3i(1))
18 {
19   if (!v->getTemporalConfig().hasTime()) {
20     throw std::runtime_error(
21         "these tests only legal for temporally varying volumes");
22   }
23 
24   const float sampleTolerance = 0.f;
25 
26   VKLVolume vklVolume   = v->getVKLVolume(getOpenVKLDevice());
27   VKLSampler vklSampler = vklNewSampler(vklVolume);
28   vklCommit(vklSampler);
29 
30   multidim_index_sequence<3> mis(v->getDimensions() / step);
31 
32   for (const auto &offset : mis) {
33     const auto offsetWithStep = offset * step;
34 
35     const vec3f objectCoordinates =
36         v->transformLocalToObjectCoordinates(offsetWithStep);
37 
38     INFO("offset = " << offsetWithStep.x << " " << offsetWithStep.y << " "
39                      << offsetWithStep.z);
40     INFO("objectCoordinates = " << objectCoordinates.x << " "
41                                 << objectCoordinates.y << " "
42                                 << objectCoordinates.z);
43 
44     std::vector<vec3f> proceduralGradients;
45 
46     for (float time : {0.f, .25f, .5f, .75f, 1.0f}) {
47       INFO("time = " << time);
48       proceduralGradients.clear();
49       for (unsigned int a = 0; a < v->getNumAttributes(); a++) {
50         proceduralGradients.push_back(
51             v->computeProceduralGradient(objectCoordinates, a, time));
52       }
53 
54       for (unsigned int a = 0; a < v->getNumAttributes(); a++) {
55         INFO("attribute index = " << a);
56         test_scalar_and_vector_gradients(vklSampler,
57                                          objectCoordinates,
58                                          proceduralGradients[a],
59                                          sampleTolerance,
60                                          a,
61                                          time);
62       }
63     }
64   }
65 
66   vklRelease(vklSampler);
67 }
68 
69 // this tests temporally unstructured with varying time step counts per voxel;
70 // other tests currently use a constant number of time steps per voxel
gradients_on_vertices_vs_procedural_values_varying_TUV_data()71 inline void gradients_on_vertices_vs_procedural_values_varying_TUV_data()
72 {
73   auto volume = vklNewVolume(getOpenVKLDevice(), "structuredRegular");
74 
75   const vec3i dimensions(3);
76   const vec3f gridOrigin(0.f);
77   const vec3f gridSpacing(1.f);
78   vklSetVec3i(volume, "dimensions", dimensions.x, dimensions.y, dimensions.z);
79   vklSetVec3f(volume, "gridOrigin", gridOrigin.x, gridOrigin.y, gridOrigin.z);
80   vklSetVec3f(
81       volume, "gridSpacing", gridSpacing.x, gridSpacing.y, gridSpacing.z);
82 
83   std::vector<unsigned int> indices(28, 0);
84   std::vector<float> times(72, 0.f);
85   std::vector<float> voxels(72, 0.f);
86 
87   size_t indexSum = 0;
88   for (size_t z = 0; z < 3; z++) {
89     for (size_t y = 0; y < 3; y++) {
90       for (size_t x = 0; x < 3; x++) {
91         size_t numTimeSamples                 = x == 0 ? 2 : 3;
92         size_t index                          = z * 9 + y * 3 + x;
93         indices[index]                        = indexSum;
94         times[indexSum]                       = 0.f;
95         voxels[indexSum]                      = 0.f;
96         times[indexSum + numTimeSamples - 1]  = 1.0f;
97         voxels[indexSum + numTimeSamples - 1] = x + y + z;
98         if (x > 0) {
99           times[indexSum + 1]  = 0.5f;
100           voxels[indexSum + 1] = 0.5f * (x + y + z);
101         }
102         indexSum += numTimeSamples;
103       }
104     }
105   }
106   indices[27] = indexSum;
107 
108   VKLData data =
109       vklNewData(getOpenVKLDevice(), voxels.size(), VKL_FLOAT, voxels.data());
110   VKLData indicesData =
111       vklNewData(getOpenVKLDevice(), indices.size(), VKL_UINT, indices.data());
112   VKLData timesData =
113       vklNewData(getOpenVKLDevice(), times.size(), VKL_FLOAT, times.data());
114 
115   vklSetData(volume, "data", data);
116   vklSetData(volume, "temporallyUnstructuredIndices", indicesData);
117   vklSetData(volume, "temporallyUnstructuredTimes", timesData);
118 
119   vklRelease(data);
120   vklRelease(indicesData);
121   vklRelease(timesData);
122 
123   vklCommit(volume);
124 
125   const float sampleTolerance = 0.005f;
126 
127   VKLSampler vklSampler = vklNewSampler(volume);
128   vklCommit(vklSampler);
129 
130   multidim_index_sequence<3> mis(dimensions);
131 
132   for (float time : {0.f, .25f, .5f, .75f, 1.0f}) {
133     for (const auto &offset : mis) {
134       const auto offsetWithStep = offset;
135       if ((reduce_min(offset) == 0 || offset.x == dimensions.x - 1 ||
136            offset.y == dimensions.y - 1 || offset.z == dimensions.z - 1)) {
137         continue;
138       }
139 
140       const vec3f objectCoordinates = offsetWithStep;
141 
142       INFO("offset = " << offsetWithStep.x << " " << offsetWithStep.y << " "
143                        << offsetWithStep.z);
144       INFO("objectCoordinates = " << objectCoordinates.x << " "
145                                   << objectCoordinates.y << " "
146                                   << objectCoordinates.z);
147       INFO("time = " << time);
148 
149       test_scalar_and_vector_gradients(
150           vklSampler, objectCoordinates, vec3f(time), sampleTolerance, 0, time);
151     }
152   }
153 
154   vklRelease(vklSampler);
155   vklRelease(volume);
156 }
157 
158 TEST_CASE("Structured regular volume gradient sampling with motion blur",
159           "[volume_sampling]")
160 {
161   initializeOpenVKL();
162 
163   SECTION("temporally unstructured with varying time steps per voxel")
164   {
165     gradients_on_vertices_vs_procedural_values_varying_TUV_data();
166   }
167 
168   const vec3i dimensions(32);
169   const vec3f gridOrigin(0.f);
170   const vec3f gridSpacing(1.f / (32.f - 1.f));
171 
172   const std::vector<TemporalConfig> temporalConfigs{
173       TemporalConfig(TemporalConfig::Structured, 2),
174       TemporalConfig(TemporalConfig::Structured, 4),
175       TemporalConfig(TemporalConfig::Unstructured, 2),
176       TemporalConfig(std::vector<float>{0.f, 0.15f, 0.3f, 0.65f, 0.9f, 1.0f})};
177 
178   const std::vector<VKLDataCreationFlags> dataCreationFlags{
179       VKL_DATA_DEFAULT, VKL_DATA_SHARED_BUFFER};
180 
181   std::random_device rd;
182   rkcommon::utility::pcg32_biased_float_distribution dist(rd(), 0, 0.f, 1.f);
183 
184   for (auto tc = 0; tc < temporalConfigs.size(); tc++) {
185     for (const auto &dcf : dataCreationFlags) {
186       std::stringstream sectionName;
187       sectionName << "temporal config " << tc << " "
188                   << (dcf == VKL_DATA_DEFAULT ? "VKL_DATA_DEFAULT"
189                                               : "VKL_DATA_SHARED_BUFFER");
190 
191       DYNAMIC_SECTION(sectionName.str())
192       {
193         std::shared_ptr<TestingStructuredVolumeMulti> v(
194             generateMultiAttributeStructuredRegularVolumeMBGradients(
195                 dimensions,
196                 gridOrigin,
197                 gridSpacing,
198                 temporalConfigs[tc],
199                 dcf,
200                 false));
201 
202         VKLVolume vklVolume = v->getVKLVolume(getOpenVKLDevice());
203         REQUIRE(vklGetNumAttributes(vklVolume) == v->getNumAttributes());
204 
205         gradients_on_vertices_vs_procedural_values_motion_blur(v, 2);
206 
207         for (float time : {0.f, dist(), dist(), 1.0f}) {
208           for (unsigned int i = 0; i < v->getNumAttributes(); i++) {
209             test_stream_gradients(v, i, time);
210           }
211         }
212       }
213     }
214   }
215 
216   shutdownOpenVKL();
217 }
218