diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2018-03-01 13:56:01 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2018-03-01 13:56:01 +0300 |
commit | 1852e702abc1dfd6c600de71d3b16bfe29459ee1 (patch) | |
tree | 6b92e4847482267c998df97d273b518a42ceb31a /intern/cycles/render | |
parent | bcafdc82d83f70312859c9a045c92daa326afbdf (diff) | |
parent | 7377d411b47d50cd943cd33e3e55c0409bb79f91 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/render/attribute.cpp | 18 | ||||
-rw-r--r-- | intern/cycles/render/attribute.h | 2 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 10 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 2 | ||||
-rw-r--r-- | intern/cycles/render/mesh.cpp | 87 | ||||
-rw-r--r-- | intern/cycles/render/mesh.h | 13 | ||||
-rw-r--r-- | intern/cycles/render/mesh_volume.cpp | 581 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 3 |
9 files changed, 700 insertions, 17 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 580d76e7777..b7248354abd 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRC mesh.cpp mesh_displace.cpp mesh_subdivision.cpp + mesh_volume.cpp nodes.cpp object.cpp osl.cpp diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 6816f8ca3f3..8c77687d9cc 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -535,9 +535,23 @@ void AttributeSet::resize(bool reserve_only) } } -void AttributeSet::clear() +void AttributeSet::clear(bool preserve_voxel_data) { - attributes.clear(); + if(preserve_voxel_data) { + list<Attribute>::iterator it; + + for(it = attributes.begin(); it != attributes.end();) { + if(it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) { + it++; + } + else { + attributes.erase(it++); + } + } + } + else { + attributes.clear(); + } } /* AttributeRequest */ diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 9e23345675d..5cb6c75aab2 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -123,7 +123,7 @@ public: void remove(Attribute *attribute); void resize(bool reserve_only = false); - void clear(); + void clear(bool preserve_voxel_data = false); }; /* AttributeRequest diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index de46599e1db..9c5e32e8219 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -84,6 +84,16 @@ bool ImageManager::set_animation_frame_update(int frame) return false; } +device_memory *ImageManager::image_memory(int flat_slot) +{ + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); + + Image *img = images[type][slot]; + + return img->mem; +} + bool ImageManager::get_image_metadata(const string& filename, void *builtin_data, ImageMetaData& metadata) diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 989416e089a..5391490d993 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -85,6 +85,8 @@ public: void set_osl_texture_system(void *texture_system); bool set_animation_frame_update(int frame); + device_memory *image_memory(int flat_slot); + bool need_update; /* NOTE: Here pixels_size is a size of storage, which equals to diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 5bcb47deb65..23b855acdc9 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -446,6 +446,7 @@ Mesh::Mesh() geometry_flags = GEOMETRY_NONE; + volume_isovalue = 0.001f; has_volume = false; has_surface_bssrdf = false; @@ -533,7 +534,7 @@ void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners) subd_attributes.resize(true); } -void Mesh::clear() +void Mesh::clear(bool preserve_voxel_data) { /* clear all verts and triangles */ verts.clear(); @@ -556,15 +557,18 @@ void Mesh::clear() subd_creases.clear(); - attributes.clear(); curve_attributes.clear(); subd_attributes.clear(); - used_shaders.clear(); + attributes.clear(preserve_voxel_data); + + if(!preserve_voxel_data) { + used_shaders.clear(); + geometry_flags = GEOMETRY_NONE; + } transform_applied = false; transform_negative_scaled = false; transform_normal = transform_identity(); - geometry_flags = GEOMETRY_NONE; delete patch_table; patch_table = NULL; @@ -1892,17 +1896,22 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * delete bvh; } -void MeshManager::device_update_flags(Device * /*device*/, - DeviceScene * /*dscene*/, - Scene * scene, - Progress& /*progress*/) +void MeshManager::device_update_preprocess(Device *device, + Scene *scene, + Progress& progress) { if(!need_update && !need_flags_update) { return; } - /* update flags */ + + progress.set_status("Updating Meshes Flags"); + + /* Update flags. */ + bool volume_images_updated = false; + foreach(Mesh *mesh, scene->meshes) { mesh->has_volume = false; + foreach(const Shader *shader, mesh->used_shaders) { if(shader->has_volume) { mesh->has_volume = true; @@ -1911,7 +1920,29 @@ void MeshManager::device_update_flags(Device * /*device*/, mesh->has_surface_bssrdf = true; } } + + if(need_update && mesh->has_volume) { + /* Create volume meshes if there is voxel data. */ + bool has_voxel_attributes = false; + + foreach(Attribute& attr, mesh->attributes.attributes) { + if(attr.element == ATTR_ELEMENT_VOXEL) { + has_voxel_attributes = true; + } + } + + if(has_voxel_attributes) { + if(!volume_images_updated) { + progress.set_status("Updating Meshes Volume Bounds"); + device_update_volume_images(device, scene, progress); + volume_images_updated = true; + } + + create_volume_mesh(scene, mesh, progress); + } + } } + need_flags_update = false; } @@ -1954,6 +1985,44 @@ void MeshManager::device_update_displacement_images(Device *device, pool.wait_work(); } +void MeshManager::device_update_volume_images(Device *device, + Scene *scene, + Progress& progress) +{ + progress.set_status("Updating Volume Images"); + TaskPool pool; + ImageManager *image_manager = scene->image_manager; + set<int> volume_images; + + foreach(Mesh *mesh, scene->meshes) { + if(!mesh->need_update) { + continue; + } + + foreach(Attribute& attr, mesh->attributes.attributes) { + if(attr.element != ATTR_ELEMENT_VOXEL) { + continue; + } + + VoxelAttribute *voxel = attr.data_voxel(); + + if(voxel->slot != -1) { + volume_images.insert(voxel->slot); + } + } + } + + foreach(int slot, volume_images) { + pool.push(function_bind(&ImageManager::device_update_slot, + image_manager, + device, + scene, + slot, + &progress)); + } + pool.wait_work(); +} + void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { if(!need_update) diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 07d8bbdbf31..c0d1513bee0 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -202,7 +202,8 @@ public: array<int> triangle_patch; /* must be < 0 for non subd triangles */ array<float2> vert_patch_uv; - bool has_volume; /* Set in the device_update_flags(). */ + float volume_isovalue; + bool has_volume; /* Set in the device_update_flags(). */ bool has_surface_bssrdf; /* Set in the device_update_flags(). */ array<float3> curve_keys; @@ -264,7 +265,7 @@ public: void reserve_curves(int numcurves, int numkeys); void resize_subd_faces(int numfaces, int num_ngons, int numcorners); void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); - void clear(); + void clear(bool preserve_voxel_data = false); void add_vertex(float3 P); void add_vertex_slow(float3 P); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); @@ -335,13 +336,15 @@ public: void update_osl_attributes(Device *device, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); + void device_update_preprocess(Device *device, Scene *scene, Progress& progress); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); + void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); + protected: /* Calculate verts/triangles/curves offsets in global arrays. */ void mesh_calc_offset(Scene *scene); @@ -370,6 +373,10 @@ protected: void device_update_displacement_images(Device *device, Scene *scene, Progress& progress); + + void device_update_volume_images(Device *device, + Scene *scene, + Progress& progress); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp new file mode 100644 index 00000000000..be43154fd93 --- /dev/null +++ b/intern/cycles/render/mesh_volume.cpp @@ -0,0 +1,581 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/mesh.h" +#include "render/attribute.h" +#include "render/scene.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_progress.h" +#include "util/util_types.h" + +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(y == -1 || y >= resolution.y) { + return -1; + } + + if(z == -1 || z >= resolution.z) { + return -1; + } + + return x + y*resolution.x + z*resolution.x*resolution.y; +} + +struct QuadData { + int v0, v1, v2, v3; + + 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, +}; + +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 }, +}; + +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), +}; + +static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int face_index) +{ + size_t vertex_offset = vertices.size(); + + QuadData quad; + quad.v0 = vertex_offset + 0; + quad.v1 = vertex_offset + 1; + quad.v2 = vertex_offset + 2; + quad.v3 = vertex_offset + 3; + quad.normal = quads_normals[face_index]; + + quads.push_back(quad); + + vertices.push_back(corners[quads_indices[face_index][0]]); + vertices.push_back(corners[quads_indices[face_index][1]]); + vertices.push_back(corners[quads_indices[face_index][2]]); + vertices.push_back(corners[quads_indices[face_index][3]]); +} + +struct VolumeParams { + int3 resolution; + float3 cell_size; + float3 start_point; + int pad_size; +}; + +static const int CUBE_SIZE = 8; + +/* Create a mesh from a volume. + * + * The way the algorithm works is as follows: + * + * - the coordinates of active voxels from a dense volume (or 3d image) are + * gathered inside an auxialliary volume. + * - each set of coordinates of an CUBE_SIZE cube are mapped to the same + * coordinate of the auxilliary volume. + * - quads are created between active and non-active voxels in the auxialliary + * 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; + + /* 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; + + /* 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; + +public: + VolumeMeshBuilder(VolumeParams *volume_params); + + void add_node(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); + +private: + void generate_vertices_and_quads(vector<int3> &vertices_is, + vector<QuadData> &quads); + + void deduplicate_vertices(vector<int3> &vertices, + vector<QuadData> &quads); + + 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); +}; + +VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params) +{ + 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); + + /* 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); + + 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; + + assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0)); + + 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; + } + + ++number_of_nodes; + + 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); + } + } + } +} + +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; + + generate_vertices_and_quads(vertices_is, quads); + + deduplicate_vertices(vertices_is, quads); + + convert_object_space(vertices_is, vertices); + + convert_quads_to_tris(quads, indices, face_normals); +} + +void VolumeMeshBuilder::generate_vertices_and_quads( + vector<ccl::int3> &vertices_is, + vector<QuadData> &quads) +{ + /* Overallocation, we could count the number of quads and vertices to create + * in a pre-pass if memory becomes an issue. */ + vertices_is.reserve(number_of_nodes*8); + quads.reserve(number_of_nodes*6); + + 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, 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, 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, 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, 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, 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, QUAD_Z_MAX); + } + } + } + } +} + +void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices, + vector<QuadData> &quads) +{ + vector<int3> sorted_vertices = vertices; + std::sort(sorted_vertices.begin(), sorted_vertices.end()); + vector<int3>::iterator it = std::unique(sorted_vertices.begin(), sorted_vertices.end()); + sorted_vertices.resize(std::distance(sorted_vertices.begin(), it)); + + vector<QuadData> new_quads = quads; + + for(size_t i = 0; i < vertices.size(); ++i) { + for(size_t j = 0; j < sorted_vertices.size(); ++j) { + if(vertices[i] != sorted_vertices[j]) { + continue; + } + + for(int k = 0; k < quads.size(); ++k) { + if(quads[k].v0 == i) { + new_quads[k].v0 = j; + } + else if(quads[k].v1 == i) { + new_quads[k].v1 = j; + } + else if(quads[k].v2 == i) { + new_quads[k].v2 = j; + } + else if(quads[k].v3 == i) { + new_quads[k].v3 = j; + } + } + + break; + } + } + + vertices = sorted_vertices; + quads = new_quads; +} + +void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices, + vector<float3> &out_vertices) +{ + 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; + + 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); + + 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); + + 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); + } +} + +/* ************************************************************************** */ + +/* For debugging: render the created mesh using the default diffuse shader. */ +//#define RENDER_DIFFUSE + +struct VoxelAttributeGrid { + float *data; + int channels; +}; + +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; + } + + int pad_size = 0; + + foreach(Shader *shader, mesh->used_shaders) { + if(!shader->has_volume) { + continue; + } + + 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); + } + } + + /* 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; + + 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]; + + if(voxel_grid.channels == 1) { + if(voxel_grid.data[voxel_index] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } + } + else if(voxel_grid.channels == 3) { + voxel_index = compute_voxel_index(resolution, x*3, y, z); + + if(voxel_grid.data[voxel_index] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } + + if(voxel_grid.data[voxel_index + 1] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } + + if(voxel_grid.data[voxel_index + 2] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } + } + else if(voxel_grid.channels == 4) { + voxel_index = compute_voxel_index(resolution, x*4, y, z); + + /* check alpha first */ + if(voxel_grid.data[voxel_index + 3] < isovalue) { + continue; + } + + if(voxel_grid.data[voxel_index] >= isovalue) { + builder.add_node_with_padding(x, y, z); + continue; + } + + if(voxel_grid.data[voxel_index + 1] >= isovalue) { + builder.add_node_with_padding(x, y, z); + continue; + } + + if(voxel_grid.data[voxel_index + 2] >= isovalue) { + builder.add_node_with_padding(x, y, z); + continue; + } + } + } + } + } + } + + vector<float3> vertices; + vector<int> indices; + vector<float3> face_normals; + builder.create_mesh(vertices, indices, face_normals); + +#ifdef RENDER_DIFFUSE + int shader = mesh->used_shaders[0]->id; +#else + int shader = mesh->shader[0]; +#endif + + mesh->clear(true); + mesh->reserve_mesh(vertices.size(), indices.size()/3); + + 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], shader, 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]; + } + + 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 diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index e34601a36a9..24923b650e3 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -204,8 +204,7 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel() || device->have_error()) return; - progress.set_status("Updating Meshes Flags"); - mesh_manager->device_update_flags(device, &dscene, this, progress); + mesh_manager->device_update_preprocess(device, this, progress); if(progress.get_cancel() || device->have_error()) return; |