Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/render/mesh_volume.cpp')
-rw-r--r--intern/cycles/render/mesh_volume.cpp728
1 files changed, 364 insertions, 364 deletions
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
index 3ee4124ba0f..a1d61fd4db7 100644
--- a/intern/cycles/render/mesh_volume.cpp
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -27,98 +27,106 @@ CCL_NAMESPACE_BEGIN
static size_t compute_voxel_index(const int3 &resolution, size_t x, size_t y, size_t z)
{
- if(x == -1 || x >= resolution.x) {
- return -1;
- }
+ if (x == -1 || x >= resolution.x) {
+ return -1;
+ }
- if(y == -1 || y >= resolution.y) {
- return -1;
- }
+ if (y == -1 || y >= resolution.y) {
+ return -1;
+ }
- if(z == -1 || z >= resolution.z) {
- return -1;
- }
+ if (z == -1 || z >= resolution.z) {
+ return -1;
+ }
- return x + y*resolution.x + z*resolution.x*resolution.y;
+ return x + y * resolution.x + z * resolution.x * resolution.y;
}
struct QuadData {
- int v0, v1, v2, v3;
+ int v0, v1, v2, v3;
- float3 normal;
+ float3 normal;
};
enum {
- QUAD_X_MIN = 0,
- QUAD_X_MAX = 1,
- QUAD_Y_MIN = 2,
- QUAD_Y_MAX = 3,
- QUAD_Z_MIN = 4,
- QUAD_Z_MAX = 5,
+ QUAD_X_MIN = 0,
+ QUAD_X_MAX = 1,
+ QUAD_Y_MIN = 2,
+ QUAD_Y_MAX = 3,
+ QUAD_Z_MIN = 4,
+ QUAD_Z_MAX = 5,
};
const int quads_indices[6][4] = {
- /* QUAD_X_MIN */
- { 4, 0, 3, 7 },
- /* QUAD_X_MAX */
- { 1, 5, 6, 2 },
- /* QUAD_Y_MIN */
- { 4, 5, 1, 0 },
- /* QUAD_Y_MAX */
- { 3, 2, 6, 7 },
- /* QUAD_Z_MIN */
- { 0, 1, 2, 3 },
- /* QUAD_Z_MAX */
- { 5, 4, 7, 6 },
+ /* QUAD_X_MIN */
+ {4, 0, 3, 7},
+ /* QUAD_X_MAX */
+ {1, 5, 6, 2},
+ /* QUAD_Y_MIN */
+ {4, 5, 1, 0},
+ /* QUAD_Y_MAX */
+ {3, 2, 6, 7},
+ /* QUAD_Z_MIN */
+ {0, 1, 2, 3},
+ /* QUAD_Z_MAX */
+ {5, 4, 7, 6},
};
const float3 quads_normals[6] = {
- /* QUAD_X_MIN */
- make_float3(-1.0f, 0.0f, 0.0f),
- /* QUAD_X_MAX */
- make_float3(1.0f, 0.0f, 0.0f),
- /* QUAD_Y_MIN */
- make_float3(0.0f, -1.0f, 0.0f),
- /* QUAD_Y_MAX */
- make_float3(0.0f, 1.0f, 0.0f),
- /* QUAD_Z_MIN */
- make_float3(0.0f, 0.0f, -1.0f),
- /* QUAD_Z_MAX */
- make_float3(0.0f, 0.0f, 1.0f),
+ /* QUAD_X_MIN */
+ make_float3(-1.0f, 0.0f, 0.0f),
+ /* QUAD_X_MAX */
+ make_float3(1.0f, 0.0f, 0.0f),
+ /* QUAD_Y_MIN */
+ make_float3(0.0f, -1.0f, 0.0f),
+ /* QUAD_Y_MAX */
+ make_float3(0.0f, 1.0f, 0.0f),
+ /* QUAD_Z_MIN */
+ make_float3(0.0f, 0.0f, -1.0f),
+ /* QUAD_Z_MAX */
+ make_float3(0.0f, 0.0f, 1.0f),
};
-static int add_vertex(int3 v, vector<int3> &vertices, int3 res, unordered_map<size_t, int> &used_verts)
+static int add_vertex(int3 v,
+ vector<int3> &vertices,
+ int3 res,
+ unordered_map<size_t, int> &used_verts)
{
- size_t vert_key = v.x + v.y * (res.x+1) + v.z * (res.x+1)*(res.y+1);
- unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
+ size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1);
+ unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
- if(it != used_verts.end()) {
- return it->second;
- }
+ if (it != used_verts.end()) {
+ return it->second;
+ }
- int vertex_offset = vertices.size();
- used_verts[vert_key] = vertex_offset;
- vertices.push_back(v);
- return vertex_offset;
+ int vertex_offset = vertices.size();
+ used_verts[vert_key] = vertex_offset;
+ vertices.push_back(v);
+ return vertex_offset;
}
-static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int3 res, unordered_map<size_t, int> &used_verts, int face_index)
+static void create_quad(int3 corners[8],
+ vector<int3> &vertices,
+ vector<QuadData> &quads,
+ int3 res,
+ unordered_map<size_t, int> &used_verts,
+ int face_index)
{
- QuadData quad;
- quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
- quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
- quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
- quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
- quad.normal = quads_normals[face_index];
-
- quads.push_back(quad);
+ QuadData quad;
+ quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
+ quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
+ quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
+ quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
+ quad.normal = quads_normals[face_index];
+
+ quads.push_back(quad);
}
struct VolumeParams {
- int3 resolution;
- float3 cell_size;
- float3 start_point;
- int pad_size;
+ int3 resolution;
+ float3 cell_size;
+ float3 start_point;
+ int pad_size;
};
static const int CUBE_SIZE = 8;
@@ -135,373 +143,365 @@ static const int CUBE_SIZE = 8;
* volume to generate a tight mesh around the volume.
*/
class VolumeMeshBuilder {
- /* Auxilliary volume that is used to check if a node already added. */
- vector<char> grid;
+ /* Auxilliary volume that is used to check if a node already added. */
+ vector<char> grid;
- /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE
- * of the original volume on each axis. */
- int3 res;
+ /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE
+ * of the original volume on each axis. */
+ int3 res;
- size_t number_of_nodes;
+ size_t number_of_nodes;
- /* Offset due to padding in the original grid. Padding will transform the
- * coordinates of the original grid from 0...res to -padding...res+padding,
- * so some coordinates are negative, and we need to properly account for
- * them. */
- int3 pad_offset;
+ /* Offset due to padding in the original grid. Padding will transform the
+ * coordinates of the original grid from 0...res to -padding...res+padding,
+ * so some coordinates are negative, and we need to properly account for
+ * them. */
+ int3 pad_offset;
- VolumeParams *params;
+ VolumeParams *params;
-public:
- VolumeMeshBuilder(VolumeParams *volume_params);
+ public:
+ VolumeMeshBuilder(VolumeParams *volume_params);
- void add_node(int x, int y, int z);
+ void add_node(int x, int y, int z);
- void add_node_with_padding(int x, int y, int z);
+ void add_node_with_padding(int x, int y, int z);
- void create_mesh(vector<float3> &vertices,
- vector<int> &indices,
- vector<float3> &face_normals);
+ void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals);
-private:
- void generate_vertices_and_quads(vector<int3> &vertices_is,
- vector<QuadData> &quads);
+ private:
+ void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
- void convert_object_space(const vector<int3> &vertices,
- vector<float3> &out_vertices);
+ void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices);
- void convert_quads_to_tris(const vector<QuadData> &quads,
- vector<int> &tris,
- vector<float3> &face_normals);
+ void convert_quads_to_tris(const vector<QuadData> &quads,
+ vector<int> &tris,
+ vector<float3> &face_normals);
};
VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
{
- params = volume_params;
- number_of_nodes = 0;
+ params = volume_params;
+ number_of_nodes = 0;
- const size_t x = divide_up(params->resolution.x, CUBE_SIZE);
- const size_t y = divide_up(params->resolution.y, CUBE_SIZE);
- const size_t z = divide_up(params->resolution.z, CUBE_SIZE);
+ const size_t x = divide_up(params->resolution.x, CUBE_SIZE);
+ const size_t y = divide_up(params->resolution.y, CUBE_SIZE);
+ const size_t z = divide_up(params->resolution.z, CUBE_SIZE);
- /* Adding 2*pad_size since we pad in both positive and negative directions
- * along the axis. */
- const size_t px = divide_up(params->resolution.x + 2*params->pad_size, CUBE_SIZE);
- const size_t py = divide_up(params->resolution.y + 2*params->pad_size, CUBE_SIZE);
- const size_t pz = divide_up(params->resolution.z + 2*params->pad_size, CUBE_SIZE);
+ /* Adding 2*pad_size since we pad in both positive and negative directions
+ * along the axis. */
+ const size_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE);
+ const size_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE);
+ const size_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE);
- res = make_int3(px, py, pz);
- pad_offset = make_int3(px - x, py - y, pz - z);
+ res = make_int3(px, py, pz);
+ pad_offset = make_int3(px - x, py - y, pz - z);
- grid.resize(px*py*pz, 0);
+ grid.resize(px * py * pz, 0);
}
void VolumeMeshBuilder::add_node(int x, int y, int z)
{
- /* Map coordinates to index space. */
- const int index_x = (x/CUBE_SIZE) + pad_offset.x;
- const int index_y = (y/CUBE_SIZE) + pad_offset.y;
- const int index_z = (z/CUBE_SIZE) + pad_offset.z;
+ /* Map coordinates to index space. */
+ const int index_x = (x / CUBE_SIZE) + pad_offset.x;
+ const int index_y = (y / CUBE_SIZE) + pad_offset.y;
+ const int index_z = (z / CUBE_SIZE) + pad_offset.z;
- assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0));
+ assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0));
- const size_t index = compute_voxel_index(res, index_x, index_y, index_z);
+ const size_t index = compute_voxel_index(res, index_x, index_y, index_z);
- /* We already have a node here. */
- if(grid[index] == 1) {
- return;
- }
+ /* We already have a node here. */
+ if (grid[index] == 1) {
+ return;
+ }
- ++number_of_nodes;
+ ++number_of_nodes;
- grid[index] = 1;
+ grid[index] = 1;
}
void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
{
- for(int px = x - params->pad_size; px < x + params->pad_size; ++px) {
- for(int py = y - params->pad_size; py < y + params->pad_size; ++py) {
- for(int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) {
- add_node(px, py, pz);
- }
- }
- }
+ for (int px = x - params->pad_size; px < x + params->pad_size; ++px) {
+ for (int py = y - params->pad_size; py < y + params->pad_size; ++py) {
+ for (int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) {
+ add_node(px, py, pz);
+ }
+ }
+ }
}
void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
vector<int> &indices,
vector<float3> &face_normals)
{
- /* We create vertices in index space (is), and only convert them to object
- * space when done. */
- vector<int3> vertices_is;
- vector<QuadData> quads;
+ /* We create vertices in index space (is), and only convert them to object
+ * space when done. */
+ vector<int3> vertices_is;
+ vector<QuadData> quads;
- generate_vertices_and_quads(vertices_is, quads);
+ generate_vertices_and_quads(vertices_is, quads);
- convert_object_space(vertices_is, vertices);
+ convert_object_space(vertices_is, vertices);
- convert_quads_to_tris(quads, indices, face_normals);
+ convert_quads_to_tris(quads, indices, face_normals);
}
-void VolumeMeshBuilder::generate_vertices_and_quads(
- vector<ccl::int3> &vertices_is,
- vector<QuadData> &quads)
+void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is,
+ vector<QuadData> &quads)
{
- unordered_map<size_t, int> used_verts;
-
- for(int z = 0; z < res.z; ++z) {
- for(int y = 0; y < res.y; ++y) {
- for(int x = 0; x < res.x; ++x) {
- size_t voxel_index = compute_voxel_index(res, x, y, z);
- if(grid[voxel_index] == 0) {
- continue;
- }
-
- /* Compute min and max coords of the node in index space. */
- int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE,
- (y - pad_offset.y)*CUBE_SIZE,
- (z - pad_offset.z)*CUBE_SIZE);
-
- /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
- int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
-
- int3 corners[8] = {
- make_int3(min[0], min[1], min[2]),
- make_int3(max[0], min[1], min[2]),
- make_int3(max[0], max[1], min[2]),
- make_int3(min[0], max[1], min[2]),
- make_int3(min[0], min[1], max[2]),
- make_int3(max[0], min[1], max[2]),
- make_int3(max[0], max[1], max[2]),
- make_int3(min[0], max[1], max[2]),
- };
-
- /* Only create a quad if on the border between an active and
- * an inactive node.
- */
-
- voxel_index = compute_voxel_index(res, x - 1, y, z);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN);
- }
-
- voxel_index = compute_voxel_index(res, x + 1, y, z);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX);
- }
-
- voxel_index = compute_voxel_index(res, x, y - 1, z);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN);
- }
-
- voxel_index = compute_voxel_index(res, x, y + 1, z);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX);
- }
-
- voxel_index = compute_voxel_index(res, x, y, z - 1);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN);
- }
-
- voxel_index = compute_voxel_index(res, x, y, z + 1);
- if(voxel_index == -1 || grid[voxel_index] == 0) {
- create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX);
- }
- }
- }
- }
+ unordered_map<size_t, int> used_verts;
+
+ for (int z = 0; z < res.z; ++z) {
+ for (int y = 0; y < res.y; ++y) {
+ for (int x = 0; x < res.x; ++x) {
+ size_t voxel_index = compute_voxel_index(res, x, y, z);
+ if (grid[voxel_index] == 0) {
+ continue;
+ }
+
+ /* Compute min and max coords of the node in index space. */
+ int3 min = make_int3((x - pad_offset.x) * CUBE_SIZE,
+ (y - pad_offset.y) * CUBE_SIZE,
+ (z - pad_offset.z) * CUBE_SIZE);
+
+ /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
+ int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
+
+ int3 corners[8] = {
+ make_int3(min[0], min[1], min[2]),
+ make_int3(max[0], min[1], min[2]),
+ make_int3(max[0], max[1], min[2]),
+ make_int3(min[0], max[1], min[2]),
+ make_int3(min[0], min[1], max[2]),
+ make_int3(max[0], min[1], max[2]),
+ make_int3(max[0], max[1], max[2]),
+ make_int3(min[0], max[1], max[2]),
+ };
+
+ /* Only create a quad if on the border between an active and
+ * an inactive node.
+ */
+
+ voxel_index = compute_voxel_index(res, x - 1, y, z);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x + 1, y, z);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y - 1, z);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y + 1, z);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y, z - 1);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y, z + 1);
+ if (voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX);
+ }
+ }
+ }
+ }
}
void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
- vector<float3> &out_vertices)
+ vector<float3> &out_vertices)
{
- out_vertices.reserve(vertices.size());
+ out_vertices.reserve(vertices.size());
- for(size_t i = 0; i < vertices.size(); ++i) {
- float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z);
- vertex *= params->cell_size;
- vertex += params->start_point;
+ for (size_t i = 0; i < vertices.size(); ++i) {
+ float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z);
+ vertex *= params->cell_size;
+ vertex += params->start_point;
- out_vertices.push_back(vertex);
- }
+ out_vertices.push_back(vertex);
+ }
}
void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
vector<int> &tris,
vector<float3> &face_normals)
{
- int index_offset = 0;
- tris.resize(quads.size()*6);
- face_normals.reserve(quads.size()*2);
+ int index_offset = 0;
+ tris.resize(quads.size() * 6);
+ face_normals.reserve(quads.size() * 2);
- for(size_t i = 0; i < quads.size(); ++i) {
- tris[index_offset++] = quads[i].v0;
- tris[index_offset++] = quads[i].v2;
- tris[index_offset++] = quads[i].v1;
+ for (size_t i = 0; i < quads.size(); ++i) {
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v2;
+ tris[index_offset++] = quads[i].v1;
- face_normals.push_back(quads[i].normal);
+ face_normals.push_back(quads[i].normal);
- tris[index_offset++] = quads[i].v0;
- tris[index_offset++] = quads[i].v3;
- tris[index_offset++] = quads[i].v2;
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v3;
+ tris[index_offset++] = quads[i].v2;
- face_normals.push_back(quads[i].normal);
- }
+ face_normals.push_back(quads[i].normal);
+ }
}
/* ************************************************************************** */
struct VoxelAttributeGrid {
- float *data;
- int channels;
+ float *data;
+ int channels;
};
-void MeshManager::create_volume_mesh(Scene *scene,
- Mesh *mesh,
- Progress& progress)
+void MeshManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress)
{
- string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
- progress.set_status("Updating Mesh", msg);
-
- vector<VoxelAttributeGrid> voxel_grids;
-
- /* Compute volume parameters. */
- VolumeParams volume_params;
- volume_params.resolution = make_int3(0, 0, 0);
-
- foreach(Attribute& attr, mesh->attributes.attributes) {
- if(attr.element != ATTR_ELEMENT_VOXEL) {
- continue;
- }
-
- VoxelAttribute *voxel = attr.data_voxel();
- device_memory *image_memory = scene->image_manager->image_memory(voxel->slot);
- int3 resolution = make_int3(image_memory->data_width,
- image_memory->data_height,
- image_memory->data_depth);
-
- if(volume_params.resolution == make_int3(0, 0, 0)) {
- volume_params.resolution = resolution;
- }
- else if(volume_params.resolution != resolution) {
- VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n";
- return;
- }
-
- VoxelAttributeGrid voxel_grid;
- voxel_grid.data = static_cast<float*>(image_memory->host_pointer);
- voxel_grid.channels = image_memory->data_elements;
- voxel_grids.push_back(voxel_grid);
- }
-
- if(voxel_grids.empty()) {
- return;
- }
-
- /* Compute padding. */
- Shader *volume_shader = NULL;
- int pad_size = 0;
-
- foreach(Shader *shader, mesh->used_shaders) {
- if(!shader->has_volume) {
- continue;
- }
-
- volume_shader = shader;
-
- if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) {
- pad_size = max(1, pad_size);
- }
- else if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) {
- pad_size = max(2, pad_size);
- }
-
- break;
- }
-
- if(!volume_shader) {
- return;
- }
-
- /* Compute start point and cell size from transform. */
- Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM);
- const int3 resolution = volume_params.resolution;
- float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
- float3 cell_size = make_float3(1.0f/resolution.x,
- 1.0f/resolution.y,
- 1.0f/resolution.z);
-
- if(attr) {
- const Transform *tfm = attr->data_transform();
- const Transform itfm = transform_inverse(*tfm);
- start_point = transform_point(&itfm, start_point);
- cell_size = transform_direction(&itfm, cell_size);
- }
-
- volume_params.start_point = start_point;
- volume_params.cell_size = cell_size;
- volume_params.pad_size = pad_size;
-
- /* Build bounding mesh around non-empty volume cells. */
- VolumeMeshBuilder builder(&volume_params);
- const float isovalue = mesh->volume_isovalue;
-
- for(int z = 0; z < resolution.z; ++z) {
- for(int y = 0; y < resolution.y; ++y) {
- for(int x = 0; x < resolution.x; ++x) {
- size_t voxel_index = compute_voxel_index(resolution, x, y, z);
-
- for(size_t i = 0; i < voxel_grids.size(); ++i) {
- const VoxelAttributeGrid &voxel_grid = voxel_grids[i];
- const int channels = voxel_grid.channels;
-
- for(int c = 0; c < channels; c++) {
- if(voxel_grid.data[voxel_index * channels + c] >= isovalue) {
- builder.add_node_with_padding(x, y, z);
- break;
- }
- }
- }
- }
- }
- }
-
- /* Create mesh. */
- vector<float3> vertices;
- vector<int> indices;
- vector<float3> face_normals;
- builder.create_mesh(vertices, indices, face_normals);
-
- mesh->clear(true);
- mesh->reserve_mesh(vertices.size(), indices.size()/3);
- mesh->used_shaders.push_back(volume_shader);
-
- for(size_t i = 0; i < vertices.size(); ++i) {
- mesh->add_vertex(vertices[i]);
- }
-
- for(size_t i = 0; i < indices.size(); i += 3) {
- mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
- }
-
- Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL);
- float3 *fN = attr_fN->data_float3();
-
- for(size_t i = 0; i < face_normals.size(); ++i) {
- fN[i] = face_normals[i];
- }
-
- /* Print stats. */
- VLOG(1) << "Memory usage volume mesh: "
- << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
- << "Mb.";
-
- VLOG(1) << "Memory usage volume grid: "
- << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
- << "Mb.";
+ string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
+ progress.set_status("Updating Mesh", msg);
+
+ vector<VoxelAttributeGrid> voxel_grids;
+
+ /* Compute volume parameters. */
+ VolumeParams volume_params;
+ volume_params.resolution = make_int3(0, 0, 0);
+
+ foreach (Attribute &attr, mesh->attributes.attributes) {
+ if (attr.element != ATTR_ELEMENT_VOXEL) {
+ continue;
+ }
+
+ VoxelAttribute *voxel = attr.data_voxel();
+ device_memory *image_memory = scene->image_manager->image_memory(voxel->slot);
+ int3 resolution = make_int3(
+ image_memory->data_width, image_memory->data_height, image_memory->data_depth);
+
+ if (volume_params.resolution == make_int3(0, 0, 0)) {
+ volume_params.resolution = resolution;
+ }
+ else if (volume_params.resolution != resolution) {
+ VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n";
+ return;
+ }
+
+ VoxelAttributeGrid voxel_grid;
+ voxel_grid.data = static_cast<float *>(image_memory->host_pointer);
+ voxel_grid.channels = image_memory->data_elements;
+ voxel_grids.push_back(voxel_grid);
+ }
+
+ if (voxel_grids.empty()) {
+ return;
+ }
+
+ /* Compute padding. */
+ Shader *volume_shader = NULL;
+ int pad_size = 0;
+
+ foreach (Shader *shader, mesh->used_shaders) {
+ if (!shader->has_volume) {
+ continue;
+ }
+
+ volume_shader = shader;
+
+ if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) {
+ pad_size = max(1, pad_size);
+ }
+ else if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) {
+ pad_size = max(2, pad_size);
+ }
+
+ break;
+ }
+
+ if (!volume_shader) {
+ return;
+ }
+
+ /* Compute start point and cell size from transform. */
+ Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM);
+ const int3 resolution = volume_params.resolution;
+ float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
+ float3 cell_size = make_float3(1.0f / resolution.x, 1.0f / resolution.y, 1.0f / resolution.z);
+
+ if (attr) {
+ const Transform *tfm = attr->data_transform();
+ const Transform itfm = transform_inverse(*tfm);
+ start_point = transform_point(&itfm, start_point);
+ cell_size = transform_direction(&itfm, cell_size);
+ }
+
+ volume_params.start_point = start_point;
+ volume_params.cell_size = cell_size;
+ volume_params.pad_size = pad_size;
+
+ /* Build bounding mesh around non-empty volume cells. */
+ VolumeMeshBuilder builder(&volume_params);
+ const float isovalue = mesh->volume_isovalue;
+
+ for (int z = 0; z < resolution.z; ++z) {
+ for (int y = 0; y < resolution.y; ++y) {
+ for (int x = 0; x < resolution.x; ++x) {
+ size_t voxel_index = compute_voxel_index(resolution, x, y, z);
+
+ for (size_t i = 0; i < voxel_grids.size(); ++i) {
+ const VoxelAttributeGrid &voxel_grid = voxel_grids[i];
+ const int channels = voxel_grid.channels;
+
+ for (int c = 0; c < channels; c++) {
+ if (voxel_grid.data[voxel_index * channels + c] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Create mesh. */
+ vector<float3> vertices;
+ vector<int> indices;
+ vector<float3> face_normals;
+ builder.create_mesh(vertices, indices, face_normals);
+
+ mesh->clear(true);
+ mesh->reserve_mesh(vertices.size(), indices.size() / 3);
+ mesh->used_shaders.push_back(volume_shader);
+
+ for (size_t i = 0; i < vertices.size(); ++i) {
+ mesh->add_vertex(vertices[i]);
+ }
+
+ for (size_t i = 0; i < indices.size(); i += 3) {
+ mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
+ }
+
+ Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL);
+ float3 *fN = attr_fN->data_float3();
+
+ for (size_t i = 0; i < face_normals.size(); ++i) {
+ fN[i] = face_normals[i];
+ }
+
+ /* Print stats. */
+ VLOG(1) << "Memory usage volume mesh: "
+ << ((vertices.size() + face_normals.size()) * sizeof(float3) +
+ indices.size() * sizeof(int)) /
+ (1024.0 * 1024.0)
+ << "Mb.";
+
+ VLOG(1) << "Memory usage volume grid: "
+ << (resolution.x * resolution.y * resolution.z * sizeof(float)) / (1024.0 * 1024.0)
+ << "Mb.";
}
CCL_NAMESPACE_END