Merge branch 'master' into blender2.8

This commit is contained in:
Kévin Dietrich 2018-03-01 11:56:01 +01:00
commit 1852e702ab
11 changed files with 718 additions and 17 deletions

View File

@ -335,6 +335,8 @@ static void create_mesh_volume_attribute(BL::Object& b_ob,
if(!b_domain)
return;
mesh->volume_isovalue = b_domain.clipping();
Attribute *attr = mesh->attributes.add(std);
VoxelAttribute *volume_data = attr->data_voxel();
ImageMetaData metadata;

View File

@ -23,6 +23,7 @@ set(SRC
mesh.cpp
mesh_displace.cpp
mesh_subdivision.cpp
mesh_volume.cpp
nodes.cpp
object.cpp
osl.cpp

View File

@ -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 */

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -78,6 +78,22 @@ ccl_device_inline int3 clamp(const int3& a, int3& mn, int mx)
}
#endif /* !__KERNEL_OPENCL__ */
ccl_device_inline bool operator==(const int3 &a, const int3 &b)
{
return a.x == b.x && a.y == b.y && a.z == b.z;
}
ccl_device_inline bool operator!=(const int3 &a, const int3 &b)
{
return !(a == b);
}
ccl_device_inline bool operator<(const int3 &a, const int3 &b)
{
return a.x < b.x && a.y < b.y && a.z < b.z;
}
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_INT3_H__ */