Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/blender/blender_volume.cpp
| Show All 11 Lines | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| #include "render/colorspace.h" | #include "render/colorspace.h" | ||||
| #include "render/image.h" | #include "render/image.h" | ||||
| #include "render/image_vdb.h" | #include "render/image_vdb.h" | ||||
| #include "render/mesh.h" | |||||
| #include "render/object.h" | #include "render/object.h" | ||||
| #include "render/volume.h" | |||||
| #include "blender/blender_sync.h" | #include "blender/blender_sync.h" | ||||
| #include "blender/blender_util.h" | #include "blender/blender_util.h" | ||||
| #ifdef WITH_OPENVDB | #ifdef WITH_OPENVDB | ||||
| # include <openvdb/openvdb.h> | # include <openvdb/openvdb.h> | ||||
| openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume, | openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume, | ||||
| struct VolumeGrid *grid); | struct VolumeGrid *grid); | ||||
| ▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | bool equals(const ImageLoader &other) const override | ||||
| return b_domain == other_loader.b_domain && attribute == other_loader.attribute; | return b_domain == other_loader.b_domain && attribute == other_loader.attribute; | ||||
| } | } | ||||
| BL::FluidDomainSettings b_domain; | BL::FluidDomainSettings b_domain; | ||||
| float3 texspace_loc, texspace_size; | float3 texspace_loc, texspace_size; | ||||
| AttributeStandard attribute; | AttributeStandard attribute; | ||||
| }; | }; | ||||
| static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame) | static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, float frame) | ||||
| { | { | ||||
| BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); | BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); | ||||
| if (!b_domain) { | if (!b_domain) { | ||||
| return; | return; | ||||
| } | } | ||||
| AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY, | AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY, | ||||
| ATTR_STD_VOLUME_COLOR, | ATTR_STD_VOLUME_COLOR, | ||||
| ATTR_STD_VOLUME_FLAME, | ATTR_STD_VOLUME_FLAME, | ||||
| ATTR_STD_VOLUME_HEAT, | ATTR_STD_VOLUME_HEAT, | ||||
| ATTR_STD_VOLUME_TEMPERATURE, | ATTR_STD_VOLUME_TEMPERATURE, | ||||
| ATTR_STD_VOLUME_VELOCITY, | ATTR_STD_VOLUME_VELOCITY, | ||||
| ATTR_STD_NONE}; | ATTR_STD_NONE}; | ||||
| for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) { | for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) { | ||||
| AttributeStandard std = attributes[i]; | AttributeStandard std = attributes[i]; | ||||
| if (!mesh->need_attribute(scene, std)) { | if (!volume->need_attribute(scene, std)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| mesh->volume_clipping = b_domain.clipping(); | volume->clipping = b_domain.clipping(); | ||||
| Attribute *attr = mesh->attributes.add(std); | Attribute *attr = volume->attributes.add(std); | ||||
| ImageLoader *loader = new BlenderSmokeLoader(b_ob, std); | ImageLoader *loader = new BlenderSmokeLoader(b_ob, std); | ||||
| ImageParams params; | ImageParams params; | ||||
| params.frame = frame; | params.frame = frame; | ||||
| attr->data_voxel() = scene->image_manager->add_image(loader, params); | attr->data_voxel() = scene->image_manager->add_image(loader, params); | ||||
| } | } | ||||
| } | } | ||||
| class BlenderVolumeLoader : public VDBImageLoader { | class BlenderVolumeLoader : public VDBImageLoader { | ||||
| public: | public: | ||||
| BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name) | BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name) | ||||
| : VDBImageLoader(grid_name), b_volume(b_volume) | : VDBImageLoader(grid_name), b_volume(b_volume) | ||||
| { | { | ||||
| b_volume.grids.load(b_data.ptr.data); | b_volume.grids.load(b_data.ptr.data); | ||||
| #ifdef WITH_OPENVDB | #ifdef WITH_OPENVDB | ||||
| BL::Volume::grids_iterator b_grid_iter; | BL::Volume::grids_iterator b_grid_iter; | ||||
| for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { | for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { | ||||
| BL::VolumeGrid b_volume_grid(*b_grid_iter); | BL::VolumeGrid b_volume_grid(*b_grid_iter); | ||||
| if (b_volume_grid.name() == grid_name) { | if (b_volume_grid.name() == grid_name) { | ||||
| const bool unload = !b_volume_grid.is_loaded(); | const bool unload = !b_volume_grid.is_loaded(); | ||||
| Volume *volume = (Volume *)b_volume.ptr.data; | ::Volume *volume = (::Volume *)b_volume.ptr.data; | ||||
| VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data; | VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data; | ||||
| grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); | grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); | ||||
| if (unload) { | if (unload) { | ||||
| b_volume_grid.unload(); | b_volume_grid.unload(); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| bool equals(const ImageLoader &other) const override | bool equals(const ImageLoader &other) const override | ||||
| { | { | ||||
| /* TODO: detect multiple volume datablocks with the same filepath. */ | /* TODO: detect multiple volume datablocks with the same filepath. */ | ||||
| const BlenderVolumeLoader &other_loader = (const BlenderVolumeLoader &)other; | const BlenderVolumeLoader &other_loader = (const BlenderVolumeLoader &)other; | ||||
| return b_volume == other_loader.b_volume && grid_name == other_loader.grid_name; | return b_volume == other_loader.b_volume && grid_name == other_loader.grid_name; | ||||
| } | } | ||||
| BL::Volume b_volume; | BL::Volume b_volume; | ||||
| }; | }; | ||||
| static void sync_volume_object(BL::BlendData &b_data, BL::Object &b_ob, Scene *scene, Mesh *mesh) | static void sync_volume_object(BL::BlendData &b_data, | ||||
| BL::Object &b_ob, | |||||
| Scene *scene, | |||||
| Volume *volume) | |||||
| { | { | ||||
| BL::Volume b_volume(b_ob.data()); | BL::Volume b_volume(b_ob.data()); | ||||
| b_volume.grids.load(b_data.ptr.data); | b_volume.grids.load(b_data.ptr.data); | ||||
| BL::VolumeRender b_render(b_volume.render()); | BL::VolumeRender b_render(b_volume.render()); | ||||
| mesh->volume_clipping = b_render.clipping(); | volume->clipping = b_render.clipping(); | ||||
| mesh->volume_step_size = b_render.step_size(); | volume->step_size = b_render.step_size(); | ||||
| mesh->volume_object_space = (b_render.space() == BL::VolumeRender::space_OBJECT); | volume->object_space = (b_render.space() == BL::VolumeRender::space_OBJECT); | ||||
| /* Find grid with matching name. */ | /* Find grid with matching name. */ | ||||
| BL::Volume::grids_iterator b_grid_iter; | BL::Volume::grids_iterator b_grid_iter; | ||||
| for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { | for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { | ||||
| BL::VolumeGrid b_grid = *b_grid_iter; | BL::VolumeGrid b_grid = *b_grid_iter; | ||||
| ustring name = ustring(b_grid.name()); | ustring name = ustring(b_grid.name()); | ||||
| AttributeStandard std = ATTR_STD_NONE; | AttributeStandard std = ATTR_STD_NONE; | ||||
| Show All 11 Lines | for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { | ||||
| } | } | ||||
| else if (name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { | else if (name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { | ||||
| std = ATTR_STD_VOLUME_TEMPERATURE; | std = ATTR_STD_VOLUME_TEMPERATURE; | ||||
| } | } | ||||
| else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { | else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { | ||||
| std = ATTR_STD_VOLUME_VELOCITY; | std = ATTR_STD_VOLUME_VELOCITY; | ||||
| } | } | ||||
| if ((std != ATTR_STD_NONE && mesh->need_attribute(scene, std)) || | if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) || | ||||
| mesh->need_attribute(scene, name)) { | volume->need_attribute(scene, name)) { | ||||
| Attribute *attr = (std != ATTR_STD_NONE) ? | Attribute *attr = (std != ATTR_STD_NONE) ? | ||||
| mesh->attributes.add(std) : | volume->attributes.add(std) : | ||||
| mesh->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); | volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); | ||||
| ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string()); | ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string()); | ||||
| ImageParams params; | ImageParams params; | ||||
| params.frame = b_volume.grids.frame(); | params.frame = b_volume.grids.frame(); | ||||
| attr->data_voxel() = scene->image_manager->add_image(loader, params, false); | attr->data_voxel() = scene->image_manager->add_image(loader, params, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If the voxel attributes change, we need to rebuild the bounding mesh. */ | /* If the voxel attributes change, we need to rebuild the bounding mesh. */ | ||||
| static vector<int> get_voxel_image_slots(Mesh *mesh) | static vector<int> get_voxel_image_slots(Mesh *mesh) | ||||
| { | { | ||||
| vector<int> slots; | vector<int> slots; | ||||
| for (const Attribute &attr : mesh->attributes.attributes) { | for (const Attribute &attr : mesh->attributes.attributes) { | ||||
| if (attr.element == ATTR_ELEMENT_VOXEL) { | if (attr.element == ATTR_ELEMENT_VOXEL) { | ||||
| slots.push_back(attr.data_voxel().svm_slot()); | slots.push_back(attr.data_voxel().svm_slot()); | ||||
| } | } | ||||
| } | } | ||||
| return slots; | return slots; | ||||
| } | } | ||||
| void BlenderSync::sync_volume(BL::Object &b_ob, Mesh *mesh, const vector<Shader *> &used_shaders) | void BlenderSync::sync_volume(BL::Object &b_ob, | ||||
| Volume *volume, | |||||
| const vector<Shader *> &used_shaders) | |||||
| { | { | ||||
| vector<int> old_voxel_slots = get_voxel_image_slots(mesh); | vector<int> old_voxel_slots = get_voxel_image_slots(volume); | ||||
| mesh->clear(); | volume->clear(); | ||||
| mesh->used_shaders = used_shaders; | volume->used_shaders = used_shaders; | ||||
| if (view_layer.use_volumes) { | if (view_layer.use_volumes) { | ||||
| if (b_ob.type() == BL::Object::type_VOLUME) { | if (b_ob.type() == BL::Object::type_VOLUME) { | ||||
| /* Volume object. Create only attributes, bounding mesh will then | /* Volume object. Create only attributes, bounding mesh will then | ||||
| * be automatically generated later. */ | * be automatically generated later. */ | ||||
| sync_volume_object(b_data, b_ob, scene, mesh); | sync_volume_object(b_data, b_ob, scene, volume); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Smoke domain. */ | /* Smoke domain. */ | ||||
| sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current()); | sync_smoke_volume(scene, b_ob, volume, b_scene.frame_current()); | ||||
| } | } | ||||
| } | } | ||||
| /* Tag update. */ | /* Tag update. */ | ||||
| bool rebuild = (old_voxel_slots != get_voxel_image_slots(mesh)); | bool rebuild = (old_voxel_slots != get_voxel_image_slots(volume)); | ||||
| mesh->tag_update(scene, rebuild); | volume->tag_update(scene, rebuild); | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||