Fix T82516: Cycles crash updateding animated volumes after NanoVDB

Two issues:
* Automatic deduplication of OpenVDB grid data was failing when Cycles had
  already cleared the OpenVDB grid, causing an empty grid. Instead rely on
  Blender return the same OpenVDB grid pointer when deduplication is possible.
* The volume bounds mesh was not properly cleared when the OpenVDB grid was
  empty, causing a mismatch between mesh and voxel data.
This commit is contained in:
Brecht Van Lommel 2020-11-11 18:40:46 +01:00
parent f17dfd575c
commit 5c01ecd2bf
2 changed files with 33 additions and 52 deletions

@ -242,13 +242,6 @@ class BlenderVolumeLoader : public VDBImageLoader {
#endif #endif
} }
bool equals(const ImageLoader &other) const override
{
/* TODO: detect multiple volume datablocks with the same filepath. */
const BlenderVolumeLoader &other_loader = (const BlenderVolumeLoader &)other;
return b_volume == other_loader.b_volume && grid_name == other_loader.grid_name;
}
BL::Volume b_volume; BL::Volume b_volume;
}; };
@ -307,25 +300,10 @@ static void sync_volume_object(BL::BlendData &b_data,
} }
} }
/* If the voxel attributes change, we need to rebuild the bounding mesh. */
static vector<int> get_voxel_image_slots(Mesh *mesh)
{
vector<int> slots;
for (const Attribute &attr : mesh->attributes.attributes) {
if (attr.element == ATTR_ELEMENT_VOXEL) {
slots.push_back(attr.data_voxel().svm_slot());
}
}
return slots;
}
void BlenderSync::sync_volume(BL::Object &b_ob, void BlenderSync::sync_volume(BL::Object &b_ob,
Volume *volume, Volume *volume,
const vector<Shader *> &used_shaders) const vector<Shader *> &used_shaders)
{ {
vector<int> old_voxel_slots = get_voxel_image_slots(volume);
volume->clear(); volume->clear();
volume->used_shaders = used_shaders; volume->used_shaders = used_shaders;
@ -342,8 +320,7 @@ void BlenderSync::sync_volume(BL::Object &b_ob,
} }
/* Tag update. */ /* Tag update. */
bool rebuild = (old_voxel_slots != get_voxel_image_slots(volume)); volume->tag_update(scene, true);
volume->tag_update(scene, rebuild);
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -495,6 +495,37 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str()); string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str());
progress.set_status("Updating Mesh", msg); progress.set_status("Updating Mesh", msg);
/* Find shader and compute padding based on volume shader interpolation settings. */
Shader *volume_shader = NULL;
int pad_size = 0;
foreach (Shader *shader, volume->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;
}
/* Clear existing volume mesh, done here in case we early out due to
* empty grid or missing volume shader. */
volume->clear();
volume->need_update_rebuild = true;
if (!volume_shader) {
return;
}
/* Create volume mesh builder. */
VolumeMeshBuilder builder; VolumeMeshBuilder builder;
#ifdef WITH_OPENVDB #ifdef WITH_OPENVDB
@ -541,35 +572,11 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
} }
#endif #endif
/* If nothing to build, early out. */
if (builder.empty_grid()) { if (builder.empty_grid()) {
return; return;
} }
/* Compute padding. */
Shader *volume_shader = NULL;
int pad_size = 0;
foreach (Shader *shader, volume->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;
}
builder.add_padding(pad_size); builder.add_padding(pad_size);
/* Slightly offset vertex coordinates to avoid overlapping faces with other /* Slightly offset vertex coordinates to avoid overlapping faces with other
@ -585,11 +592,8 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
vector<float3> face_normals; vector<float3> face_normals;
builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance); builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance);
volume->clear();
volume->reserve_mesh(vertices.size(), indices.size() / 3); volume->reserve_mesh(vertices.size(), indices.size() / 3);
volume->used_shaders.push_back(volume_shader); volume->used_shaders.push_back(volume_shader);
volume->need_update = true;
volume->need_update_rebuild = true;
for (size_t i = 0; i < vertices.size(); ++i) { for (size_t i = 0; i < vertices.size(); ++i) {
volume->add_vertex(vertices[i]); volume->add_vertex(vertices[i]);