mesh_volume.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. * Copyright 2011-2016 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "render/mesh.h"
  17. #include "render/attribute.h"
  18. #include "render/scene.h"
  19. #include "util/util_foreach.h"
  20. #include "util/util_logging.h"
  21. #include "util/util_progress.h"
  22. #include "util/util_types.h"
  23. CCL_NAMESPACE_BEGIN
  24. static size_t compute_voxel_index(const int3 &resolution, size_t x, size_t y, size_t z)
  25. {
  26. if (x == -1 || x >= resolution.x) {
  27. return -1;
  28. }
  29. if (y == -1 || y >= resolution.y) {
  30. return -1;
  31. }
  32. if (z == -1 || z >= resolution.z) {
  33. return -1;
  34. }
  35. return x + y * resolution.x + z * resolution.x * resolution.y;
  36. }
  37. struct QuadData {
  38. int v0, v1, v2, v3;
  39. float3 normal;
  40. };
  41. enum {
  42. QUAD_X_MIN = 0,
  43. QUAD_X_MAX = 1,
  44. QUAD_Y_MIN = 2,
  45. QUAD_Y_MAX = 3,
  46. QUAD_Z_MIN = 4,
  47. QUAD_Z_MAX = 5,
  48. };
  49. const int quads_indices[6][4] = {
  50. /* QUAD_X_MIN */
  51. {4, 0, 3, 7},
  52. /* QUAD_X_MAX */
  53. {1, 5, 6, 2},
  54. /* QUAD_Y_MIN */
  55. {4, 5, 1, 0},
  56. /* QUAD_Y_MAX */
  57. {3, 2, 6, 7},
  58. /* QUAD_Z_MIN */
  59. {0, 1, 2, 3},
  60. /* QUAD_Z_MAX */
  61. {5, 4, 7, 6},
  62. };
  63. const float3 quads_normals[6] = {
  64. /* QUAD_X_MIN */
  65. make_float3(-1.0f, 0.0f, 0.0f),
  66. /* QUAD_X_MAX */
  67. make_float3(1.0f, 0.0f, 0.0f),
  68. /* QUAD_Y_MIN */
  69. make_float3(0.0f, -1.0f, 0.0f),
  70. /* QUAD_Y_MAX */
  71. make_float3(0.0f, 1.0f, 0.0f),
  72. /* QUAD_Z_MIN */
  73. make_float3(0.0f, 0.0f, -1.0f),
  74. /* QUAD_Z_MAX */
  75. make_float3(0.0f, 0.0f, 1.0f),
  76. };
  77. static int add_vertex(int3 v,
  78. vector<int3> &vertices,
  79. int3 res,
  80. unordered_map<size_t, int> &used_verts)
  81. {
  82. size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1);
  83. unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
  84. if (it != used_verts.end()) {
  85. return it->second;
  86. }
  87. int vertex_offset = vertices.size();
  88. used_verts[vert_key] = vertex_offset;
  89. vertices.push_back(v);
  90. return vertex_offset;
  91. }
  92. static void create_quad(int3 corners[8],
  93. vector<int3> &vertices,
  94. vector<QuadData> &quads,
  95. int3 res,
  96. unordered_map<size_t, int> &used_verts,
  97. int face_index)
  98. {
  99. QuadData quad;
  100. quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
  101. quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
  102. quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
  103. quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
  104. quad.normal = quads_normals[face_index];
  105. quads.push_back(quad);
  106. }
  107. struct VolumeParams {
  108. int3 resolution;
  109. float3 cell_size;
  110. float3 start_point;
  111. int pad_size;
  112. };
  113. static const int CUBE_SIZE = 8;
  114. /* Create a mesh from a volume.
  115. *
  116. * The way the algorithm works is as follows:
  117. *
  118. * - The coordinates of active voxels from a dense volume (or 3d image) are
  119. * gathered inside an auxiliary volume.
  120. * - Each set of coordinates of an CUBE_SIZE cube are mapped to the same
  121. * coordinate of the auxiliary volume.
  122. * - Quads are created between active and non-active voxels in the auxiliary
  123. * volume to generate a tight mesh around the volume.
  124. */
  125. class VolumeMeshBuilder {
  126. /* Auxiliary volume that is used to check if a node already added. */
  127. vector<char> grid;
  128. /* The resolution of the auxiliary volume, set to be equal to 1/CUBE_SIZE
  129. * of the original volume on each axis. */
  130. int3 res;
  131. size_t number_of_nodes;
  132. /* Offset due to padding in the original grid. Padding will transform the
  133. * coordinates of the original grid from 0...res to -padding...res+padding,
  134. * so some coordinates are negative, and we need to properly account for
  135. * them. */
  136. int3 pad_offset;
  137. VolumeParams *params;
  138. public:
  139. VolumeMeshBuilder(VolumeParams *volume_params);
  140. void add_node(int x, int y, int z);
  141. void add_node_with_padding(int x, int y, int z);
  142. void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals);
  143. private:
  144. void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
  145. void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices);
  146. void convert_quads_to_tris(const vector<QuadData> &quads,
  147. vector<int> &tris,
  148. vector<float3> &face_normals);
  149. };
  150. VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
  151. {
  152. params = volume_params;
  153. number_of_nodes = 0;
  154. const size_t x = divide_up(params->resolution.x, CUBE_SIZE);
  155. const size_t y = divide_up(params->resolution.y, CUBE_SIZE);
  156. const size_t z = divide_up(params->resolution.z, CUBE_SIZE);
  157. /* Adding 2*pad_size since we pad in both positive and negative directions
  158. * along the axis. */
  159. const size_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE);
  160. const size_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE);
  161. const size_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE);
  162. res = make_int3(px, py, pz);
  163. pad_offset = make_int3(px - x, py - y, pz - z);
  164. grid.resize(px * py * pz, 0);
  165. }
  166. void VolumeMeshBuilder::add_node(int x, int y, int z)
  167. {
  168. /* Map coordinates to index space. */
  169. const int index_x = (x / CUBE_SIZE) + pad_offset.x;
  170. const int index_y = (y / CUBE_SIZE) + pad_offset.y;
  171. const int index_z = (z / CUBE_SIZE) + pad_offset.z;
  172. assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0));
  173. const size_t index = compute_voxel_index(res, index_x, index_y, index_z);
  174. /* We already have a node here. */
  175. if (grid[index] == 1) {
  176. return;
  177. }
  178. ++number_of_nodes;
  179. grid[index] = 1;
  180. }
  181. void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
  182. {
  183. for (int px = x - params->pad_size; px < x + params->pad_size; ++px) {
  184. for (int py = y - params->pad_size; py < y + params->pad_size; ++py) {
  185. for (int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) {
  186. add_node(px, py, pz);
  187. }
  188. }
  189. }
  190. }
  191. void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
  192. vector<int> &indices,
  193. vector<float3> &face_normals)
  194. {
  195. /* We create vertices in index space (is), and only convert them to object
  196. * space when done. */
  197. vector<int3> vertices_is;
  198. vector<QuadData> quads;
  199. generate_vertices_and_quads(vertices_is, quads);
  200. convert_object_space(vertices_is, vertices);
  201. convert_quads_to_tris(quads, indices, face_normals);
  202. }
  203. void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is,
  204. vector<QuadData> &quads)
  205. {
  206. unordered_map<size_t, int> used_verts;
  207. for (int z = 0; z < res.z; ++z) {
  208. for (int y = 0; y < res.y; ++y) {
  209. for (int x = 0; x < res.x; ++x) {
  210. size_t voxel_index = compute_voxel_index(res, x, y, z);
  211. if (grid[voxel_index] == 0) {
  212. continue;
  213. }
  214. /* Compute min and max coords of the node in index space. */
  215. int3 min = make_int3((x - pad_offset.x) * CUBE_SIZE,
  216. (y - pad_offset.y) * CUBE_SIZE,
  217. (z - pad_offset.z) * CUBE_SIZE);
  218. /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
  219. int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
  220. int3 corners[8] = {
  221. make_int3(min[0], min[1], min[2]),
  222. make_int3(max[0], min[1], min[2]),
  223. make_int3(max[0], max[1], min[2]),
  224. make_int3(min[0], max[1], min[2]),
  225. make_int3(min[0], min[1], max[2]),
  226. make_int3(max[0], min[1], max[2]),
  227. make_int3(max[0], max[1], max[2]),
  228. make_int3(min[0], max[1], max[2]),
  229. };
  230. /* Only create a quad if on the border between an active and
  231. * an inactive node.
  232. */
  233. voxel_index = compute_voxel_index(res, x - 1, y, z);
  234. if (voxel_index == -1 || grid[voxel_index] == 0) {
  235. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN);
  236. }
  237. voxel_index = compute_voxel_index(res, x + 1, y, z);
  238. if (voxel_index == -1 || grid[voxel_index] == 0) {
  239. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX);
  240. }
  241. voxel_index = compute_voxel_index(res, x, y - 1, z);
  242. if (voxel_index == -1 || grid[voxel_index] == 0) {
  243. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN);
  244. }
  245. voxel_index = compute_voxel_index(res, x, y + 1, z);
  246. if (voxel_index == -1 || grid[voxel_index] == 0) {
  247. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX);
  248. }
  249. voxel_index = compute_voxel_index(res, x, y, z - 1);
  250. if (voxel_index == -1 || grid[voxel_index] == 0) {
  251. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN);
  252. }
  253. voxel_index = compute_voxel_index(res, x, y, z + 1);
  254. if (voxel_index == -1 || grid[voxel_index] == 0) {
  255. create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX);
  256. }
  257. }
  258. }
  259. }
  260. }
  261. void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
  262. vector<float3> &out_vertices)
  263. {
  264. out_vertices.reserve(vertices.size());
  265. for (size_t i = 0; i < vertices.size(); ++i) {
  266. float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z);
  267. vertex *= params->cell_size;
  268. vertex += params->start_point;
  269. out_vertices.push_back(vertex);
  270. }
  271. }
  272. void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
  273. vector<int> &tris,
  274. vector<float3> &face_normals)
  275. {
  276. int index_offset = 0;
  277. tris.resize(quads.size() * 6);
  278. face_normals.reserve(quads.size() * 2);
  279. for (size_t i = 0; i < quads.size(); ++i) {
  280. tris[index_offset++] = quads[i].v0;
  281. tris[index_offset++] = quads[i].v2;
  282. tris[index_offset++] = quads[i].v1;
  283. face_normals.push_back(quads[i].normal);
  284. tris[index_offset++] = quads[i].v0;
  285. tris[index_offset++] = quads[i].v3;
  286. tris[index_offset++] = quads[i].v2;
  287. face_normals.push_back(quads[i].normal);
  288. }
  289. }
  290. /* ************************************************************************** */
  291. struct VoxelAttributeGrid {
  292. float *data;
  293. int channels;
  294. };
  295. void MeshManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress)
  296. {
  297. string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
  298. progress.set_status("Updating Mesh", msg);
  299. vector<VoxelAttributeGrid> voxel_grids;
  300. /* Compute volume parameters. */
  301. VolumeParams volume_params;
  302. volume_params.resolution = make_int3(0, 0, 0);
  303. foreach (Attribute &attr, mesh->attributes.attributes) {
  304. if (attr.element != ATTR_ELEMENT_VOXEL) {
  305. continue;
  306. }
  307. VoxelAttribute *voxel = attr.data_voxel();
  308. device_memory *image_memory = scene->image_manager->image_memory(voxel->slot);
  309. int3 resolution = make_int3(
  310. image_memory->data_width, image_memory->data_height, image_memory->data_depth);
  311. if (volume_params.resolution == make_int3(0, 0, 0)) {
  312. volume_params.resolution = resolution;
  313. }
  314. else if (volume_params.resolution != resolution) {
  315. VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n";
  316. return;
  317. }
  318. VoxelAttributeGrid voxel_grid;
  319. voxel_grid.data = static_cast<float *>(image_memory->host_pointer);
  320. voxel_grid.channels = image_memory->data_elements;
  321. voxel_grids.push_back(voxel_grid);
  322. }
  323. if (voxel_grids.empty()) {
  324. return;
  325. }
  326. /* Compute padding. */
  327. Shader *volume_shader = NULL;
  328. int pad_size = 0;
  329. foreach (Shader *shader, mesh->used_shaders) {
  330. if (!shader->has_volume) {
  331. continue;
  332. }
  333. volume_shader = shader;
  334. if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) {
  335. pad_size = max(1, pad_size);
  336. }
  337. else if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) {
  338. pad_size = max(2, pad_size);
  339. }
  340. break;
  341. }
  342. if (!volume_shader) {
  343. return;
  344. }
  345. /* Compute start point and cell size from transform. */
  346. Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM);
  347. const int3 resolution = volume_params.resolution;
  348. float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
  349. float3 cell_size = make_float3(1.0f / resolution.x, 1.0f / resolution.y, 1.0f / resolution.z);
  350. if (attr) {
  351. const Transform *tfm = attr->data_transform();
  352. const Transform itfm = transform_inverse(*tfm);
  353. start_point = transform_point(&itfm, start_point);
  354. cell_size = transform_direction(&itfm, cell_size);
  355. }
  356. volume_params.start_point = start_point;
  357. volume_params.cell_size = cell_size;
  358. volume_params.pad_size = pad_size;
  359. /* Build bounding mesh around non-empty volume cells. */
  360. VolumeMeshBuilder builder(&volume_params);
  361. const float isovalue = mesh->volume_isovalue;
  362. for (int z = 0; z < resolution.z; ++z) {
  363. for (int y = 0; y < resolution.y; ++y) {
  364. for (int x = 0; x < resolution.x; ++x) {
  365. size_t voxel_index = compute_voxel_index(resolution, x, y, z);
  366. for (size_t i = 0; i < voxel_grids.size(); ++i) {
  367. const VoxelAttributeGrid &voxel_grid = voxel_grids[i];
  368. const int channels = voxel_grid.channels;
  369. for (int c = 0; c < channels; c++) {
  370. if (voxel_grid.data[voxel_index * channels + c] >= isovalue) {
  371. builder.add_node_with_padding(x, y, z);
  372. break;
  373. }
  374. }
  375. }
  376. }
  377. }
  378. }
  379. /* Create mesh. */
  380. vector<float3> vertices;
  381. vector<int> indices;
  382. vector<float3> face_normals;
  383. builder.create_mesh(vertices, indices, face_normals);
  384. mesh->clear(true);
  385. mesh->reserve_mesh(vertices.size(), indices.size() / 3);
  386. mesh->used_shaders.push_back(volume_shader);
  387. for (size_t i = 0; i < vertices.size(); ++i) {
  388. mesh->add_vertex(vertices[i]);
  389. }
  390. for (size_t i = 0; i < indices.size(); i += 3) {
  391. mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
  392. }
  393. Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL);
  394. float3 *fN = attr_fN->data_float3();
  395. for (size_t i = 0; i < face_normals.size(); ++i) {
  396. fN[i] = face_normals[i];
  397. }
  398. /* Print stats. */
  399. VLOG(1) << "Memory usage volume mesh: "
  400. << ((vertices.size() + face_normals.size()) * sizeof(float3) +
  401. indices.size() * sizeof(int)) /
  402. (1024.0 * 1024.0)
  403. << "Mb.";
  404. VLOG(1) << "Memory usage volume grid: "
  405. << (resolution.x * resolution.y * resolution.z * sizeof(float)) / (1024.0 * 1024.0)
  406. << "Mb.";
  407. }
  408. CCL_NAMESPACE_END