1 // Copyright 2019-2021 Intel Corporation 2 // SPDX-License-Identifier: Apache-2.0 3 4 #pragma once 5 6 #include "ProceduralVolume.h" 7 #include "TestingAMRVolume.h" 8 #include "procedural_functions.h" 9 // openvkl 10 #include "openvkl/openvkl.h" 11 // rkcommon 12 #include "rkcommon/math/vec.h" 13 #include "rkcommon/tasking/parallel_for.h" 14 // std 15 #include <algorithm> 16 #include <vector> 17 18 using namespace rkcommon; 19 20 namespace openvkl { 21 namespace testing { 22 23 template <vec3f volumeGradientFunction(const vec3f &, float) = 24 gradientNotImplemented> 25 struct ProceduralShellsAMRVolume : public TestingAMRVolume, 26 public ProceduralVolume 27 { 28 ProceduralShellsAMRVolume(const vec3i &_dimensions, 29 const vec3f &_gridOrigin, 30 const vec3f &_gridSpacing); 31 32 std::vector<unsigned char> generateVoxels() override; // unused 33 34 protected: 35 void generateVKLVolume(VKLDevice device) override; 36 37 float computeProceduralValueImpl(const vec3f &objectCoordinates, 38 float time) const override; 39 40 vec3f computeProceduralGradientImpl(const vec3f &objectCoordinates, 41 float time) const override; 42 43 int refFactor = 4; 44 int blockSize = 16; 45 const int numCells = blockSize * blockSize * blockSize; 46 }; 47 48 // Inlined definitions //////////////////////////////////////////////////// 49 50 template <vec3f volumeGradientFunction(const vec3f &, float)> 51 inline ProceduralShellsAMRVolume<volumeGradientFunction>:: ProceduralShellsAMRVolume(const vec3i & _dimensions,const vec3f & _gridOrigin,const vec3f & _gridSpacing)52 ProceduralShellsAMRVolume(const vec3i &_dimensions, 53 const vec3f &_gridOrigin, 54 const vec3f &_gridSpacing) 55 : TestingAMRVolume(_dimensions, _gridOrigin, _gridSpacing), 56 ProceduralVolume(false) 57 { 58 if (dimensions.x % blockSize != 0 || dimensions.y % blockSize != 0 || 59 dimensions.z % blockSize != 0) { 60 std::stringstream ss; 61 ss << "ProceduralShellsAMRVolume requires multiple-of-" << blockSize 62 << " dimensions"; 63 throw std::runtime_error(ss.str()); 64 } 65 } 66 67 template <vec3f volumeGradientFunction(const vec3f &, float)> 68 inline std::vector<unsigned char> generateVoxels()69 ProceduralShellsAMRVolume<volumeGradientFunction>::generateVoxels() 70 { 71 { 72 return std::vector<unsigned char>(); 73 } 74 } 75 76 template <vec3f volumeGradientFunction(const vec3f &, float)> 77 inline void generateVKLVolume(VKLDevice device)78 ProceduralShellsAMRVolume<volumeGradientFunction>::generateVKLVolume( 79 VKLDevice device) 80 { 81 int numLevels = 0; 82 int minExtent = reduce_min(dimensions); 83 if (minExtent < 128) { 84 numLevels = 2; 85 } else if (minExtent < 256) { 86 numLevels = 3; 87 blockSize = 8; 88 } else { 89 numLevels = 3; 90 } 91 92 std::vector<box3i> blockBounds; 93 std::vector<int> refinementLevels; 94 std::vector<float> cellWidths; 95 std::vector<std::vector<float>> blockDataVectors; 96 std::vector<VKLData> blockData; 97 98 // block bound upper bounds are inclusive, hence subtracting 1 99 100 float cellWidth = gridSpacing.x * float(minExtent) / blockSize; 101 int refLevel = 0; 102 std::vector<float> voxels(numCells, -0.5f); 103 104 // outer shell - takes entire world space region 105 blockBounds.emplace_back(vec3i(0), vec3i(blockSize - 1)); 106 refinementLevels.emplace_back(refLevel); 107 cellWidths.emplace_back(cellWidth); 108 blockDataVectors.emplace_back(voxels); 109 110 // for each subsequent shell, create 8 16^3 blocks with progressively 111 // smaller cell widths 112 for (int level = 1; level < numLevels; level++) { 113 cellWidth /= refFactor; 114 cellWidths.emplace_back(cellWidth); 115 116 voxels = std::vector<float>(numCells, float(level - 1)); 117 118 int lb = minExtent / 2 / std::pow(refFactor, numLevels - level - 1); 119 int ub = lb + blockSize - 1; 120 121 blockBounds.emplace_back(vec3i(lb), vec3i(ub)); 122 refinementLevels.emplace_back(level); 123 blockDataVectors.emplace_back(voxels); 124 125 blockBounds.emplace_back(vec3i(lb - blockSize, lb, lb), 126 vec3i(ub - blockSize, ub, ub)); 127 refinementLevels.emplace_back(level); 128 blockDataVectors.emplace_back(voxels); 129 130 blockBounds.emplace_back(vec3i(lb, lb - blockSize, lb), 131 vec3i(ub, ub - blockSize, ub)); 132 refinementLevels.emplace_back(level); 133 blockDataVectors.emplace_back(voxels); 134 135 blockBounds.emplace_back(vec3i(lb - blockSize, lb - blockSize, lb), 136 vec3i(ub - blockSize, ub - blockSize, ub)); 137 refinementLevels.emplace_back(level); 138 blockDataVectors.emplace_back(voxels); 139 140 blockBounds.emplace_back(vec3i(lb, lb, lb - blockSize), 141 vec3i(ub, ub, ub - blockSize)); 142 refinementLevels.emplace_back(level); 143 blockDataVectors.emplace_back(voxels); 144 145 blockBounds.emplace_back(vec3i(lb - blockSize, lb, lb - blockSize), 146 vec3i(ub - blockSize, ub, ub - blockSize)); 147 refinementLevels.emplace_back(level); 148 blockDataVectors.emplace_back(voxels); 149 150 blockBounds.emplace_back(vec3i(lb, lb - blockSize, lb - blockSize), 151 vec3i(ub, ub - blockSize, ub - blockSize)); 152 refinementLevels.emplace_back(level); 153 blockDataVectors.emplace_back(voxels); 154 155 blockBounds.emplace_back(vec3i(lb - blockSize), vec3i(ub - blockSize)); 156 refinementLevels.emplace_back(level); 157 blockDataVectors.emplace_back(voxels); 158 } 159 160 // convert the data above to VKLData objects 161 162 for (const std::vector<float> &bd : blockDataVectors) 163 blockData.push_back( 164 vklNewData(device, bd.size(), VKL_FLOAT, bd.data())); 165 166 VKLData blockDataData = 167 vklNewData(device, blockData.size(), VKL_DATA, blockData.data()); 168 169 VKLData blockBoundsData = 170 vklNewData(device, blockBounds.size(), VKL_BOX3I, blockBounds.data()); 171 172 VKLData refinementLevelsData = vklNewData( 173 device, refinementLevels.size(), VKL_INT, refinementLevels.data()); 174 175 VKLData cellWidthsData = 176 vklNewData(device, cellWidths.size(), VKL_FLOAT, cellWidths.data()); 177 178 // create the AMR volume 179 180 volume = vklNewVolume(device, "amr"); 181 182 vklSetData(volume, "block.data", blockDataData); 183 vklSetData(volume, "block.bounds", blockBoundsData); 184 vklSetData(volume, "block.level", refinementLevelsData); 185 vklSetData(volume, "cellWidth", cellWidthsData); 186 187 vklRelease(blockDataData); 188 vklRelease(blockBoundsData); 189 vklRelease(refinementLevelsData); 190 vklRelease(cellWidthsData); 191 192 for (auto &d : blockData) 193 vklRelease(d); 194 195 vklCommit(volume); 196 197 for (const auto &bdv : blockDataVectors) 198 computedValueRange.extend( 199 computeValueRange(VKL_FLOAT, bdv.data(), bdv.size())); 200 } 201 202 template <vec3f gradientFunction(const vec3f &, float)> 203 inline float computeProceduralValueImpl(const vec3f & objectCoordinates,float time)204 ProceduralShellsAMRVolume<gradientFunction>::computeProceduralValueImpl( 205 const vec3f &objectCoordinates, float time) const 206 { 207 return getShellValue(objectCoordinates, dimensions); 208 } 209 210 template <vec3f gradientFunction(const vec3f &, float)> 211 inline vec3f computeProceduralGradientImpl(const vec3f & objectCoordinates,float time)212 ProceduralShellsAMRVolume<gradientFunction>::computeProceduralGradientImpl( 213 const vec3f &objectCoordinates, float time) const 214 { 215 return gradientFunction(objectCoordinates, time); 216 } 217 218 } // namespace testing 219 } // namespace openvkl 220