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