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:
-rw-r--r--intern/cycles/blender/addon/ui.py2
-rw-r--r--intern/cycles/blender/camera.cpp10
-rw-r--r--intern/cycles/blender/object.cpp7
-rw-r--r--intern/cycles/blender/sync.cpp2
-rw-r--r--intern/cycles/blender/volume.cpp49
-rw-r--r--intern/cycles/kernel/integrator/shader_eval.h59
-rw-r--r--intern/cycles/kernel/types.h25
-rw-r--r--intern/cycles/scene/attribute.cpp9
-rw-r--r--intern/cycles/scene/camera.cpp1
-rw-r--r--intern/cycles/scene/camera.h12
-rw-r--r--intern/cycles/scene/geometry.cpp2
-rw-r--r--intern/cycles/scene/geometry.h2
-rw-r--r--intern/cycles/scene/image_vdb.cpp5
-rw-r--r--intern/cycles/scene/image_vdb.h1
-rw-r--r--intern/cycles/scene/object.cpp10
-rw-r--r--intern/cycles/scene/scene.cpp6
-rw-r--r--intern/cycles/scene/scene.h2
-rw-r--r--intern/cycles/scene/volume.cpp149
-rw-r--r--intern/cycles/scene/volume.h1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py22
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/intern/fluid.c3
-rw-r--r--source/blender/blenkernel/intern/volume.cc62
-rw-r--r--source/blender/makesdna/DNA_fluid_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h5
-rw-r--r--source/blender/makesdna/DNA_volume_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_volume_types.h17
-rw-r--r--source/blender/makesrna/RNA_enum_items.h2
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c14
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c6
-rw-r--r--source/blender/makesrna/intern/rna_volume.c59
32 files changed, 511 insertions, 48 deletions
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 739a555f037..8a7b0635ed7 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1034,7 +1034,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def poll(cls, context):
ob = context.object
if CyclesButtonsPanel.poll(context) and ob:
- if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'CURVES', 'POINTCLOUD'}:
+ if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'CURVES', 'POINTCLOUD', 'VOLUME'}:
return True
if ob.instance_type == 'COLLECTION' and ob.instance_collection:
return True
diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp
index cdd19341534..402fd7c4ec6 100644
--- a/intern/cycles/blender/camera.cpp
+++ b/intern/cycles/blender/camera.cpp
@@ -23,7 +23,7 @@ struct BlenderCamera {
float lens;
float shuttertime;
- Camera::MotionPosition motion_position;
+ MotionPosition motion_position;
array<float> shutter_curve;
Camera::RollingShutterType rolling_shutter_type;
@@ -114,7 +114,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_rende
bcam->sensor_width = 36.0f;
bcam->sensor_height = 24.0f;
bcam->sensor_fit = BlenderCamera::AUTO;
- bcam->motion_position = Camera::MOTION_POSITION_CENTER;
+ bcam->motion_position = MOTION_POSITION_CENTER;
bcam->border.right = 1.0f;
bcam->border.top = 1.0f;
bcam->viewport_camera_border.right = 1.0f;
@@ -555,10 +555,8 @@ void BlenderSync::sync_camera(BL::RenderSettings &b_render,
curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- bcam.motion_position = (Camera::MotionPosition)get_enum(cscene,
- "motion_blur_position",
- Camera::MOTION_NUM_POSITIONS,
- Camera::MOTION_POSITION_CENTER);
+ bcam.motion_position = (MotionPosition)get_enum(
+ cscene, "motion_blur_position", MOTION_NUM_POSITIONS, MOTION_POSITION_CENTER);
bcam.rolling_shutter_type = (Camera::RollingShutterType)get_enum(
cscene,
"rolling_shutter_type",
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index f77cbdf847d..9b08b564b25 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -16,6 +16,7 @@
#include "scene/shader.h"
#include "scene/shader_graph.h"
#include "scene/shader_nodes.h"
+#include "scene/volume.h"
#include "util/foreach.h"
#include "util/hash.h"
@@ -715,13 +716,13 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
float frame_center_delta = 0.0f;
if (scene->need_motion() != Scene::MOTION_PASS &&
- scene->camera->get_motion_position() != Camera::MOTION_POSITION_CENTER) {
+ scene->camera->get_motion_position() != MOTION_POSITION_CENTER) {
float shuttertime = scene->camera->get_shuttertime();
- if (scene->camera->get_motion_position() == Camera::MOTION_POSITION_END) {
+ if (scene->camera->get_motion_position() == MOTION_POSITION_END) {
frame_center_delta = -shuttertime * 0.5f;
}
else {
- assert(scene->camera->get_motion_position() == Camera::MOTION_POSITION_START);
+ assert(scene->camera->get_motion_position() == MOTION_POSITION_START);
frame_center_delta = shuttertime * 0.5f;
}
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index bd6bfafedeb..1028c940772 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -272,7 +272,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
geometry_synced.clear(); /* use for objects and motion sync */
if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
- scene->camera->get_motion_position() == Camera::MOTION_POSITION_CENTER) {
+ scene->camera->get_motion_position() == MOTION_POSITION_CENTER) {
sync_objects(b_depsgraph, b_v3d);
}
sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state);
diff --git a/intern/cycles/blender/volume.cpp b/intern/cycles/blender/volume.cpp
index 381b3385a5a..8dd2d45c0b6 100644
--- a/intern/cycles/blender/volume.cpp
+++ b/intern/cycles/blender/volume.cpp
@@ -168,7 +168,8 @@ class BlenderSmokeLoader : public ImageLoader {
AttributeStandard attribute;
};
-static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
+static void sync_smoke_volume(
+ BL::Scene &b_scene, Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
{
if (!b_ob_info.is_real_object_data()) {
return;
@@ -178,6 +179,18 @@ static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volu
return;
}
+ float velocity_scale = b_domain.velocity_scale();
+ /* Motion blur attribute is relative to seconds, we need it relative to frames. */
+ const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
+ const float motion_scale = (need_motion) ?
+ scene->motion_shutter_time() /
+ (b_scene.render().fps() / b_scene.render().fps_base()) :
+ 0.0f;
+
+ velocity_scale *= motion_scale;
+
+ volume->set_velocity_scale(velocity_scale);
+
AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
ATTR_STD_VOLUME_COLOR,
ATTR_STD_VOLUME_FLAME,
@@ -234,6 +247,7 @@ class BlenderVolumeLoader : public VDBImageLoader {
};
static void sync_volume_object(BL::BlendData &b_data,
+ BL::Scene &b_scene,
BObjectInfo &b_ob_info,
Scene *scene,
Volume *volume)
@@ -247,6 +261,20 @@ static void sync_volume_object(BL::BlendData &b_data,
volume->set_step_size(b_render.step_size());
volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
+ float velocity_scale = b_volume.velocity_scale();
+ if (b_volume.velocity_unit() == BL::Volume::velocity_unit_SECOND) {
+ /* Motion blur attribute is relative to seconds, we need it relative to frames. */
+ const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
+ const float motion_scale = (need_motion) ?
+ scene->motion_shutter_time() /
+ (b_scene.render().fps() / b_scene.render().fps_base()) :
+ 0.0f;
+
+ velocity_scale *= motion_scale;
+ }
+
+ volume->set_velocity_scale(velocity_scale);
+
/* Find grid with matching name. */
for (BL::VolumeGrid &b_grid : b_volume.grids) {
ustring name = ustring(b_grid.name());
@@ -267,9 +295,22 @@ static void sync_volume_object(BL::BlendData &b_data,
else if (name == Attribute::standard_name(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) ||
+ name == b_volume.velocity_grid()) {
std = ATTR_STD_VOLUME_VELOCITY;
}
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY_X) ||
+ name == b_volume.velocity_x_grid()) {
+ std = ATTR_STD_VOLUME_VELOCITY_X;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY_Y) ||
+ name == b_volume.velocity_y_grid()) {
+ std = ATTR_STD_VOLUME_VELOCITY_Y;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY_Z) ||
+ name == b_volume.velocity_z_grid()) {
+ std = ATTR_STD_VOLUME_VELOCITY_Z;
+ }
if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) ||
volume->need_attribute(scene, name)) {
@@ -294,11 +335,11 @@ void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
if (b_ob_info.object_data.is_a(&RNA_Volume)) {
/* Volume object. Create only attributes, bounding mesh will then
* be automatically generated later. */
- sync_volume_object(b_data, b_ob_info, scene, volume);
+ sync_volume_object(b_data, b_scene, b_ob_info, scene, volume);
}
else {
/* Smoke domain. */
- sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
+ sync_smoke_volume(b_scene, scene, b_ob_info, volume, b_scene.frame_current());
}
}
diff --git a/intern/cycles/kernel/integrator/shader_eval.h b/intern/cycles/kernel/integrator/shader_eval.h
index 3066fb661a1..3ea53b3e647 100644
--- a/intern/cycles/kernel/integrator/shader_eval.h
+++ b/intern/cycles/kernel/integrator/shader_eval.h
@@ -831,6 +831,65 @@ ccl_device_inline void shader_eval_volume(KernelGlobals kg,
/* todo: this is inefficient for motion blur, we should be
* caching matrices instead of recomputing them each step */
shader_setup_object_transforms(kg, sd, sd->time);
+
+ if ((sd->object_flag & SD_OBJECT_HAS_VOLUME_MOTION) != 0) {
+ AttributeDescriptor v_desc = find_attribute(kg, sd, ATTR_STD_VOLUME_VELOCITY);
+ kernel_assert(v_desc.offset != ATTR_STD_NOT_FOUND);
+
+ const float3 P = sd->P;
+ const float velocity_scale = kernel_tex_fetch(__objects, sd->object).velocity_scale;
+ const float time_offset = kernel_data.cam.motion_position == MOTION_POSITION_CENTER ?
+ 0.5f :
+ 0.0f;
+ const float time = kernel_data.cam.motion_position == MOTION_POSITION_END ?
+ (1.0f - kernel_data.cam.shuttertime) + sd->time :
+ sd->time;
+
+ /* Use a 1st order semi-lagrangian advection scheme to estimate what volume quantity
+ * existed, or will exist, at the given time:
+ *
+ * `phi(x, T) = phi(x - (T - t) * u(x, T), t)`
+ *
+ * where
+ *
+ * x : position
+ * T : super-sampled time (or ray time)
+ * t : current time of the simulation (in rendering we assume this is center frame with
+ * relative time = 0)
+ * phi : the volume quantity
+ * u : the velocity field
+ *
+ * But first we need to determine the velocity field `u(x, T)`, which we can estimate also
+ * using semi-lagrangian advection.
+ *
+ * `u(x, T) = u(x - (T - t) * u(x, T), t)`
+ *
+ * This is the typical way to model self-advection in fluid dynamics, however, we do not
+ * account for other forces affecting the velocity during simulation (pressure, buyoancy,
+ * etc.): this gives a linear interpolation when fluid are mostly "curvy". For better
+ * results, a higher order interpolation scheme can be used (at the cost of more lookups),
+ * or an interpolation of the velocity fields for the previous and next frames could also
+ * be used to estimate `u(x, T)` (which will cost more memory and lookups).
+ *
+ * References:
+ * "Eulerian Motion Blur", Kim and Ko, 2007
+ * "Production Volume Rendering", Wreninge et al., 2012
+ */
+
+ /* Find velocity. */
+ float3 velocity = primitive_volume_attribute_float3(kg, sd, v_desc);
+ object_dir_transform(kg, sd, &velocity);
+
+ /* Find advected P. */
+ sd->P = P - (time - time_offset) * velocity_scale * velocity;
+
+ /* Find advected velocity. */
+ velocity = primitive_volume_attribute_float3(kg, sd, v_desc);
+ object_dir_transform(kg, sd, &velocity);
+
+ /* Find advected P. */
+ sd->P = P - (time - time_offset) * velocity_scale * velocity;
+ }
# endif
}
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 422285cd346..01df7948241 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -489,6 +489,18 @@ enum PanoramaType {
PANORAMA_NUM_TYPES,
};
+/* Specifies an offset for the shutter's time interval. */
+enum MotionPosition {
+ /* Shutter opens at the current frame. */
+ MOTION_POSITION_START = 0,
+ /* Shutter is fully open at the current frame. */
+ MOTION_POSITION_CENTER = 1,
+ /* Shutter closes at the current frame. */
+ MOTION_POSITION_END = 2,
+
+ MOTION_NUM_POSITIONS,
+};
+
/* Direct Light Sampling */
enum DirectLightSamplingType {
@@ -635,6 +647,9 @@ typedef enum AttributeStandard {
ATTR_STD_VOLUME_HEAT,
ATTR_STD_VOLUME_TEMPERATURE,
ATTR_STD_VOLUME_VELOCITY,
+ ATTR_STD_VOLUME_VELOCITY_X,
+ ATTR_STD_VOLUME_VELOCITY_Y,
+ ATTR_STD_VOLUME_VELOCITY_Z,
ATTR_STD_POINTINESS,
ATTR_STD_RANDOM_PER_ISLAND,
ATTR_STD_SHADOW_TRANSPARENCY,
@@ -808,6 +823,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_CAUSTICS_CASTER = (1 << 9),
/* object is caustics receiver */
SD_OBJECT_CAUSTICS_RECEIVER = (1 << 10),
+ /* object has attribute for volume motion */
+ SD_OBJECT_HAS_VOLUME_MOTION = (1 << 11),
/* object is using caustics */
SD_OBJECT_CAUSTICS = (SD_OBJECT_CAUSTICS_CASTER | SD_OBJECT_CAUSTICS_RECEIVER),
@@ -815,7 +832,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED |
SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER |
- SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS)
+ SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS |
+ SD_OBJECT_HAS_VOLUME_MOTION)
};
typedef struct ccl_align(16) ShaderData
@@ -1040,7 +1058,7 @@ typedef struct KernelCamera {
int rolling_shutter_type;
float rolling_shutter_duration;
- int pad;
+ int motion_position;
} KernelCamera;
static_assert_align(KernelCamera, 16);
@@ -1386,7 +1404,8 @@ typedef struct KernelObject {
uint visibility;
int primitive_type;
- int pad1;
+ /* Volume velocity scale. */
+ float velocity_scale;
} KernelObject;
static_assert_align(KernelObject, 16);
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
index 0ca602362bc..df01189a54b 100644
--- a/intern/cycles/scene/attribute.cpp
+++ b/intern/cycles/scene/attribute.cpp
@@ -360,6 +360,12 @@ const char *Attribute::standard_name(AttributeStandard std)
return "temperature";
case ATTR_STD_VOLUME_VELOCITY:
return "velocity";
+ case ATTR_STD_VOLUME_VELOCITY_X:
+ return "velocity_x";
+ case ATTR_STD_VOLUME_VELOCITY_Y:
+ return "velocity_y";
+ case ATTR_STD_VOLUME_VELOCITY_Z:
+ return "velocity_z";
case ATTR_STD_POINTINESS:
return "pointiness";
case ATTR_STD_RANDOM_PER_ISLAND:
@@ -587,6 +593,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_VOLUME_FLAME:
case ATTR_STD_VOLUME_HEAT:
case ATTR_STD_VOLUME_TEMPERATURE:
+ case ATTR_STD_VOLUME_VELOCITY_X:
+ case ATTR_STD_VOLUME_VELOCITY_Y:
+ case ATTR_STD_VOLUME_VELOCITY_Z:
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
break;
case ATTR_STD_VOLUME_COLOR:
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
index 6aca2fcbb81..710f1c5ee90 100644
--- a/intern/cycles/scene/camera.cpp
+++ b/intern/cycles/scene/camera.cpp
@@ -397,6 +397,7 @@ void Camera::update(Scene *scene)
/* motion blur */
kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
+ kcam->motion_position = motion_position;
/* type */
kcam->type = camera_type;
diff --git a/intern/cycles/scene/camera.h b/intern/cycles/scene/camera.h
index 97bee430588..c150405acc2 100644
--- a/intern/cycles/scene/camera.h
+++ b/intern/cycles/scene/camera.h
@@ -30,18 +30,6 @@ class Camera : public Node {
public:
NODE_DECLARE
- /* Specifies an offset for the shutter's time interval. */
- enum MotionPosition {
- /* Shutter opens at the current frame. */
- MOTION_POSITION_START = 0,
- /* Shutter is fully open at the current frame. */
- MOTION_POSITION_CENTER = 1,
- /* Shutter closes at the current frame. */
- MOTION_POSITION_END = 2,
-
- MOTION_NUM_POSITIONS,
- };
-
/* Specifies rolling shutter effect. */
enum RollingShutterType {
/* No rolling shutter effect. */
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
index 351ec4f09ae..349d8ad39c7 100644
--- a/intern/cycles/scene/geometry.cpp
+++ b/intern/cycles/scene/geometry.cpp
@@ -1541,7 +1541,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
}
Volume *volume = static_cast<Volume *>(geom);
- create_volume_mesh(volume, progress);
+ create_volume_mesh(scene, volume, progress);
/* always reallocate when we have a volume, as we need to rebuild the BVH */
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h
index 0c2e70d483d..6210a64509a 100644
--- a/intern/cycles/scene/geometry.h
+++ b/intern/cycles/scene/geometry.h
@@ -216,7 +216,7 @@ class GeometryManager {
protected:
bool displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress);
- void create_volume_mesh(Volume *volume, Progress &progress);
+ void create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress);
/* Attributes */
void update_osl_attributes(Device *device,
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
index 9906606a959..8f30433c229 100644
--- a/intern/cycles/scene/image_vdb.cpp
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -66,6 +66,11 @@ struct ToNanoOp {
# endif
#endif
+VDBImageLoader::VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name)
+ : grid_name(grid_name), grid(grid_)
+{
+}
+
VDBImageLoader::VDBImageLoader(const string &grid_name) : grid_name(grid_name)
{
}
diff --git a/intern/cycles/scene/image_vdb.h b/intern/cycles/scene/image_vdb.h
index c851ef6250d..4c1aba80af8 100644
--- a/intern/cycles/scene/image_vdb.h
+++ b/intern/cycles/scene/image_vdb.h
@@ -17,6 +17,7 @@ CCL_NAMESPACE_BEGIN
class VDBImageLoader : public ImageLoader {
public:
+ VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name);
VDBImageLoader(const string &grid_name);
~VDBImageLoader();
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 55d89fc3673..c57d26464ed 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -439,6 +439,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
flag |= SD_OBJECT_HAS_VERTEX_MOTION;
}
}
+ else if (geom->is_volume()) {
+ Volume *volume = static_cast<Volume *>(geom);
+ if (volume->attributes.find(ATTR_STD_VOLUME_VELOCITY) &&
+ volume->get_velocity_scale() != 0.0f) {
+ flag |= SD_OBJECT_HAS_VOLUME_MOTION;
+ kobject.velocity_scale = volume->get_velocity_scale();
+ }
+ }
if (state->need_motion == Scene::MOTION_PASS) {
/* Clear motion array if there is no actual motion. */
@@ -488,7 +496,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.dupli_generated[2] = ob->dupli_generated[2];
kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
static_cast<Hair *>(geom)->get_curve_keys().size() :
- (geom->geometry_type == Geometry::POINTCLOUD) ?
+ (geom->geometry_type == Geometry::POINTCLOUD) ?
static_cast<PointCloud *>(geom)->num_points() :
0;
kobject.dupli_uv[0] = ob->dupli_uv[0];
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index b6b53004816..b35242139ea 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -381,7 +381,7 @@ void Scene::device_update(Device *device_, Progress &progress)
}
}
-Scene::MotionType Scene::need_motion()
+Scene::MotionType Scene::need_motion() const
{
if (integrator->get_motion_blur())
return MOTION_BLUR;
@@ -407,6 +407,10 @@ bool Scene::need_global_attribute(AttributeStandard std)
return need_motion() != MOTION_NONE;
else if (std == ATTR_STD_MOTION_VERTEX_NORMAL)
return need_motion() == MOTION_BLUR;
+ else if (std == ATTR_STD_VOLUME_VELOCITY || std == ATTR_STD_VOLUME_VELOCITY_X ||
+ std == ATTR_STD_VOLUME_VELOCITY_Y || std == ATTR_STD_VOLUME_VELOCITY_Z) {
+ return need_motion() != MOTION_NONE;
+ }
return false;
}
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
index 54c7d9d93ea..a0d2f4a6c06 100644
--- a/intern/cycles/scene/scene.h
+++ b/intern/cycles/scene/scene.h
@@ -257,7 +257,7 @@ class Scene : public NodeOwner {
void need_global_attributes(AttributeRequestSet &attributes);
enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
- MotionType need_motion();
+ MotionType need_motion() const;
float motion_shutter_time();
bool need_update();
diff --git a/intern/cycles/scene/volume.cpp b/intern/cycles/scene/volume.cpp
index 0555fdd2fad..1357d5ed762 100644
--- a/intern/cycles/scene/volume.cpp
+++ b/intern/cycles/scene/volume.cpp
@@ -10,9 +10,9 @@
# include <openvdb/tools/Dense.h>
# include <openvdb/tools/GridTransformer.h>
# include <openvdb/tools/Morphology.h>
+# include <openvdb/tools/Statistics.h>
#endif
-#include "util/foreach.h"
#include "util/hash.h"
#include "util/log.h"
#include "util/openvdb.h"
@@ -28,6 +28,7 @@ NODE_DEFINE(Volume)
SOCKET_FLOAT(clipping, "Clipping", 0.001f);
SOCKET_FLOAT(step_size, "Step Size", 0.0f);
SOCKET_BOOLEAN(object_space, "Object Space", false);
+ SOCKET_FLOAT(velocity_scale, "Velocity Scale", 1.0f);
return type;
}
@@ -482,11 +483,141 @@ static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_textu
return sparse;
}
+
+static int estimate_required_velocity_padding(openvdb::GridBase::ConstPtr grid,
+ float velocity_scale)
+{
+ /* TODO: we may need to also find outliers and clamp them to avoid adding too much padding. */
+ openvdb::math::Extrema extrema;
+ openvdb::Vec3d voxel_size;
+
+ /* External .vdb files have a vec3 type for velocity, but the Blender exporter creates a vec4. */
+ if (grid->isType<openvdb::Vec3fGrid>()) {
+ openvdb::Vec3fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid);
+ extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn());
+ voxel_size = vel_grid->voxelSize();
+ }
+ else if (grid->isType<openvdb::Vec4fGrid>()) {
+ openvdb::Vec4fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec4fGrid>(grid);
+ extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn());
+ voxel_size = vel_grid->voxelSize();
+ }
+ else {
+ assert(0);
+ return 0;
+ }
+
+ /* We should only have uniform grids, so x = y = z, but we never know. */
+ const double max_voxel_size = openvdb::math::Max(voxel_size.x(), voxel_size.y(), voxel_size.z());
+ if (max_voxel_size == 0.0) {
+ return 0;
+ }
+
+ const double estimated_padding = extrema.max() * static_cast<double>(velocity_scale) /
+ max_voxel_size;
+
+ return static_cast<int>(std::ceil(estimated_padding));
+}
+
+static openvdb::FloatGrid::ConstPtr get_vdb_for_attribute(Volume *volume, AttributeStandard std)
+{
+ Attribute *attr = volume->attributes.find(std);
+ if (!attr) {
+ return nullptr;
+ }
+
+ ImageHandle &handle = attr->data_voxel();
+ VDBImageLoader *vdb_loader = handle.vdb_loader();
+ if (!vdb_loader) {
+ return nullptr;
+ }
+
+ openvdb::GridBase::ConstPtr grid = vdb_loader->get_grid();
+ if (!grid) {
+ return nullptr;
+ }
+
+ if (!grid->isType<openvdb::FloatGrid>()) {
+ return nullptr;
+ }
+
+ return openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid);
+}
+
+class MergeScalarGrids {
+ typedef openvdb::FloatTree ScalarTree;
+
+ openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z;
+
+ public:
+ MergeScalarGrids(const ScalarTree *x_tree, const ScalarTree *y_tree, const ScalarTree *z_tree)
+ : m_acc_x(*x_tree), m_acc_y(*y_tree), m_acc_z(*z_tree)
+ {
+ }
+
+ MergeScalarGrids(const MergeScalarGrids &other)
+ : m_acc_x(other.m_acc_x), m_acc_y(other.m_acc_y), m_acc_z(other.m_acc_z)
+ {
+ }
+
+ void operator()(const openvdb::Vec3STree::ValueOnIter &it) const
+ {
+ using namespace openvdb;
+
+ const math::Coord xyz = it.getCoord();
+ float x = m_acc_x.getValue(xyz);
+ float y = m_acc_y.getValue(xyz);
+ float z = m_acc_z.getValue(xyz);
+
+ it.setValue(math::Vec3s(x, y, z));
+ }
+};
+
+static void merge_scalar_grids_for_velocity(const Scene *scene, Volume *volume)
+{
+ if (volume->attributes.find(ATTR_STD_VOLUME_VELOCITY)) {
+ /* A vector grid for velocity is already available. */
+ return;
+ }
+
+ openvdb::FloatGrid::ConstPtr vel_x_grid = get_vdb_for_attribute(volume,
+ ATTR_STD_VOLUME_VELOCITY_X);
+ openvdb::FloatGrid::ConstPtr vel_y_grid = get_vdb_for_attribute(volume,
+ ATTR_STD_VOLUME_VELOCITY_Y);
+ openvdb::FloatGrid::ConstPtr vel_z_grid = get_vdb_for_attribute(volume,
+ ATTR_STD_VOLUME_VELOCITY_Z);
+
+ if (!(vel_x_grid && vel_y_grid && vel_z_grid)) {
+ return;
+ }
+
+ openvdb::Vec3fGrid::Ptr vecgrid = openvdb::Vec3SGrid::create(openvdb::Vec3s(0.0f));
+
+ /* Activate voxels in the vector grid based on the scalar grids to ensure thread safety during
+ * the merge. */
+ vecgrid->tree().topologyUnion(vel_x_grid->tree());
+ vecgrid->tree().topologyUnion(vel_y_grid->tree());
+ vecgrid->tree().topologyUnion(vel_z_grid->tree());
+
+ MergeScalarGrids op(&vel_x_grid->tree(), &vel_y_grid->tree(), &vel_z_grid->tree());
+ openvdb::tools::foreach (vecgrid->beginValueOn(), op, true, false);
+
+ /* Assume all grids have the same transformation. */
+ openvdb::math::Transform::Ptr transform = openvdb::ConstPtrCast<openvdb::math::Transform>(
+ vel_x_grid->transformPtr());
+ vecgrid->setTransform(transform);
+
+ /* Make an attribute for it. */
+ Attribute *attr = volume->attributes.add(ATTR_STD_VOLUME_VELOCITY);
+ ImageLoader *loader = new VDBImageLoader(vecgrid, "merged_velocity");
+ ImageParams params;
+ attr->data_voxel() = scene->image_manager->add_image(loader, params);
+}
#endif
/* ************************************************************************** */
-void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
+void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress)
{
string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str());
progress.set_status("Updating Mesh", msg);
@@ -495,7 +626,7 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
Shader *volume_shader = NULL;
int pad_size = 0;
- foreach (Node *node, volume->get_used_shaders()) {
+ for (Node *node : volume->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (!shader->has_volume) {
@@ -529,7 +660,9 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
VolumeMeshBuilder builder;
#ifdef WITH_OPENVDB
- foreach (Attribute &attr, volume->attributes.attributes) {
+ merge_scalar_grids_for_velocity(scene, volume);
+
+ for (Attribute &attr : volume->attributes.attributes) {
if (attr.element != ATTR_ELEMENT_VOXEL) {
continue;
}
@@ -567,9 +700,17 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
}
if (grid) {
+ /* Add padding based on the maximum velocity vector. */
+ if (attr.std == ATTR_STD_VOLUME_VELOCITY && scene->need_motion() != Scene::MOTION_NONE) {
+ pad_size = max(pad_size,
+ estimate_required_velocity_padding(grid, volume->get_velocity_scale()));
+ }
+
builder.add_grid(grid, do_clipping, volume->get_clipping());
}
}
+#else
+ (void)scene;
#endif
/* If nothing to build, early out. */
diff --git a/intern/cycles/scene/volume.h b/intern/cycles/scene/volume.h
index cae0f5f5bce..2b94aaf5253 100644
--- a/intern/cycles/scene/volume.h
+++ b/intern/cycles/scene/volume.h
@@ -18,6 +18,7 @@ class Volume : public Mesh {
NODE_SOCKET_API(float, clipping)
NODE_SOCKET_API(float, step_size)
NODE_SOCKET_API(bool, object_space)
+ NODE_SOCKET_API(float, velocity_scale)
virtual void clear(bool preserve_shaders = false) override;
};
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index 9fdcd4c1faa..678972a677c 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -115,6 +115,12 @@ class DATA_PT_volume_render(DataButtonsPanel, Panel):
col = layout.column(align=True)
col.prop(render, "clipping")
+ col = layout.column(align=False)
+ col.prop(volume, "velocity_grid")
+
+ col.prop(volume, "velocity_unit")
+ col.prop(volume, "velocity_scale")
+
class DATA_PT_volume_viewport_display(DataButtonsPanel, Panel):
bl_label = "Viewport Display"
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 1b03da490b9..88f8658035b 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -1485,6 +1485,27 @@ class PHYSICS_PT_viewport_display_advanced(PhysicButtonsPanel, Panel):
note.label(icon='INFO', text="Range highlighting for flags is not available!")
+class PHYSICS_PT_fluid_domain_render(PhysicButtonsPanel, Panel):
+ bl_label = "Render"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+ layout.prop(domain, "velocity_scale")
+
+
classes = (
FLUID_PT_presets,
PHYSICS_PT_fluid,
@@ -1513,6 +1534,7 @@ classes = (
PHYSICS_PT_viewport_display_color,
PHYSICS_PT_viewport_display_debug,
PHYSICS_PT_viewport_display_advanced,
+ PHYSICS_PT_fluid_domain_render,
)
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 77f01e7919d..8791469360a 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -77,6 +77,11 @@ const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volum
/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
+/* Tries to set the name of the velocity field. If no such grid exists with the given base name,
+ * this will try common postfixes in order to detect velocity fields split into multiple grids.
+ * Return false if neither finding with the base name nor with the postfixes succeeded. */
+bool BKE_volume_set_velocity_grid_by_name(struct Volume *volume, const char *base_name);
+
/* Grid
*
* By default only grid metadata is loaded, for access to the tree and voxels
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 81e73b6cf2c..efb33294efd 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -5071,6 +5071,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
tfds->openvdb_compression = fds->openvdb_compression;
tfds->clipping = fds->clipping;
tfds->openvdb_data_depth = fds->openvdb_data_depth;
+
+ /* Render options. */
+ tfds->velocity_scale = fds->velocity_scale;
}
else if (tfmd->flow) {
FluidFlowSettings *tffs = tfmd->flow;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 0c131863edd..307466d7dc9 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -60,6 +60,7 @@ using blender::float3;
using blender::float4x4;
using blender::IndexRange;
using blender::StringRef;
+using blender::StringRefNull;
#ifdef WITH_OPENVDB
# include <atomic>
@@ -517,6 +518,8 @@ static void volume_init_data(ID *id)
MEMCPY_STRUCT_AFTER(volume, DNA_struct_default_get(Volume), id);
BKE_volume_init_grids(volume);
+
+ BLI_strncpy(volume->velocity_grid, "velocity", sizeof(volume->velocity_grid));
}
static void volume_copy_data(Main *UNUSED(bmain),
@@ -794,6 +797,57 @@ bool BKE_volume_is_loaded(const Volume *volume)
#endif
}
+bool BKE_volume_set_velocity_grid_by_name(Volume *volume, const char *base_name)
+{
+ const StringRefNull ref_base_name = base_name;
+
+ if (BKE_volume_grid_find_for_read(volume, base_name)) {
+ BLI_strncpy(volume->velocity_grid, base_name, sizeof(volume->velocity_grid));
+ volume->runtime.velocity_x_grid[0] = '\0';
+ volume->runtime.velocity_y_grid[0] = '\0';
+ volume->runtime.velocity_z_grid[0] = '\0';
+ return true;
+ }
+
+ /* It could be that the velocity grid is split in multiple grids, try with known postfixes. */
+ const StringRefNull postfixes[][3] = {{"x", "y", "z"}, {".x", ".y", ".z"}, {"_x", "_y", "_z"}};
+
+ for (const StringRefNull *postfix : postfixes) {
+ bool found = true;
+ for (int i = 0; i < 3; i++) {
+ std::string post_fixed_name = ref_base_name + postfix[i];
+ if (!BKE_volume_grid_find_for_read(volume, post_fixed_name.c_str())) {
+ found = false;
+ break;
+ }
+ }
+
+ if (!found) {
+ continue;
+ }
+
+ /* Save the base name as well. */
+ BLI_strncpy(volume->velocity_grid, base_name, sizeof(volume->velocity_grid));
+ BLI_strncpy(volume->runtime.velocity_x_grid,
+ (ref_base_name + postfix[0]).c_str(),
+ sizeof(volume->runtime.velocity_x_grid));
+ BLI_strncpy(volume->runtime.velocity_y_grid,
+ (ref_base_name + postfix[1]).c_str(),
+ sizeof(volume->runtime.velocity_y_grid));
+ BLI_strncpy(volume->runtime.velocity_z_grid,
+ (ref_base_name + postfix[2]).c_str(),
+ sizeof(volume->runtime.velocity_z_grid));
+ return true;
+ }
+
+ /* Reset to avoid potential issues. */
+ volume->velocity_grid[0] = '\0';
+ volume->runtime.velocity_x_grid[0] = '\0';
+ volume->runtime.velocity_y_grid[0] = '\0';
+ volume->runtime.velocity_z_grid[0] = '\0';
+ return false;
+}
+
bool BKE_volume_load(const Volume *volume, const Main *bmain)
{
#ifdef WITH_OPENVDB
@@ -857,6 +911,14 @@ bool BKE_volume_load(const Volume *volume, const Main *bmain)
}
}
+ /* Try to detect the velocity grid. */
+ const char *common_velocity_names[] = {"velocity", "vel", "v"};
+ for (const char *common_velocity_name : common_velocity_names) {
+ if (BKE_volume_set_velocity_grid_by_name(const_cast<Volume *>(volume), common_velocity_name)) {
+ break;
+ }
+ }
+
BLI_strncpy(grids.filepath, filepath, FILE_MAX);
return grids.error_msg.empty();
diff --git a/source/blender/makesdna/DNA_fluid_defaults.h b/source/blender/makesdna/DNA_fluid_defaults.h
index fd48585792f..90a91c6c995 100644
--- a/source/blender/makesdna/DNA_fluid_defaults.h
+++ b/source/blender/makesdna/DNA_fluid_defaults.h
@@ -187,6 +187,7 @@
.cache_comp = SM_CACHE_LIGHT, \
.cache_high_comp = SM_CACHE_LIGHT, \
.cache_file_format = 0, \
+ .velocity_scale = 1.0f, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 11780d99af8..5a1636879bb 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -670,7 +670,10 @@ typedef struct FluidDomainSettings {
char interp_method;
char gridlines_color_field; /* Simulation field used to color map onto gridlines. */
char gridlines_cell_filter;
- char _pad10[7]; /* Unused. */
+ char _pad10[3]; /* Unused. */
+
+ /* Velocity factor for motion blur rendering. */
+ float velocity_scale;
/* OpenVDB cache options. */
int openvdb_compression;
diff --git a/source/blender/makesdna/DNA_volume_defaults.h b/source/blender/makesdna/DNA_volume_defaults.h
index 2025d664d40..ee98f0ea4fd 100644
--- a/source/blender/makesdna/DNA_volume_defaults.h
+++ b/source/blender/makesdna/DNA_volume_defaults.h
@@ -36,7 +36,8 @@
.frame_duration = 0, \
.display = _DNA_DEFAULT_VolumeDisplay, \
.render = _DNA_DEFAULT_VolumeRender, \
- }
+ .velocity_scale = 1.0f, \
+}
/** \} */
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index f2f53bc910f..a2e558aa790 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -24,6 +24,11 @@ typedef struct Volume_Runtime {
/** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
+
+ /* Names for scalar grids which would need to be merged to recompose the velocity grid. */
+ char velocity_x_grid[64];
+ char velocity_y_grid[64];
+ char velocity_z_grid[64];
} Volume_Runtime;
typedef struct VolumeDisplay {
@@ -75,6 +80,18 @@ typedef struct Volume {
VolumeRender render;
VolumeDisplay display;
+ /* Velocity field name. */
+ char velocity_grid[64];
+
+ char _pad3[3];
+
+ /* Unit of time the velocity vectors are expressed in.
+ * This uses the same enumeration values as #CacheFile.velocity_unit. */
+ char velocity_unit;
+
+ /* Factor for velocity vector for artistic control. */
+ float velocity_scale;
+
/* Draw Cache */
void *batch_cache;
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 6e2c898d691..6539d636697 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -212,6 +212,8 @@ DEF_ENUM(rna_enum_subdivision_boundary_smooth_items)
DEF_ENUM(rna_enum_transform_orientation_items)
+DEF_ENUM(rna_enum_velocity_unit_items)
+
/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 62b08ebb281..c8b154b9b04 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -14,6 +14,12 @@
#include "rna_internal.h"
+const EnumPropertyItem rna_enum_velocity_unit_items[] = {
+ {CACHEFILE_VELOCITY_UNIT_SECOND, "SECOND", 0, "Second", ""},
+ {CACHEFILE_VELOCITY_UNIT_FRAME, "FRAME", 0, "Frame", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -350,15 +356,9 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- static const EnumPropertyItem velocity_unit_items[] = {
- {CACHEFILE_VELOCITY_UNIT_SECOND, "SECOND", 0, "Second", ""},
- {CACHEFILE_VELOCITY_UNIT_FRAME, "FRAME", 0, "Frame", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
prop = RNA_def_property(srna, "velocity_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "velocity_unit");
- RNA_def_property_enum_items(prop, velocity_unit_items);
+ RNA_def_property_enum_items(prop, rna_enum_velocity_unit_items);
RNA_def_property_ui_text(
prop,
"Velocity Unit",
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index dab3cd68d4c..e0ec146a248 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -2644,6 +2644,12 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, gridlines_cell_filter_items);
RNA_def_property_ui_text(prop, "Cell Type", "Cell type to be highlighted");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "velocity_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Velocity Scale", "Factor to control the amount of motion blur");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update");
}
static void rna_def_fluid_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 5b323629a80..12cb35b239d 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -78,6 +78,15 @@ static void rna_Volume_update_is_sequence(Main *bmain, Scene *scene, PointerRNA
DEG_relations_tag_update(bmain);
}
+static void rna_Volume_velocity_grid_set(PointerRNA *ptr, const char *value)
+{
+ Volume *volume = (Volume *)ptr->data;
+ if (!BKE_volume_set_velocity_grid_by_name(volume, value)) {
+ WM_reportf(RPT_ERROR, "Could not find grid with name %s", value);
+ }
+ WM_main_add_notifier(NC_GEOM | ND_DATA, volume);
+}
+
/* Grid */
static void rna_VolumeGrid_name_get(PointerRNA *ptr, char *value)
@@ -248,6 +257,7 @@ static void rna_def_volume_grid(BlenderRNA *brna)
RNA_def_property_string_funcs(
prop, "rna_VolumeGrid_name_get", "rna_VolumeGrid_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Volume grid name");
+ RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -619,6 +629,55 @@ static void rna_def_volume(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "VolumeRender");
RNA_def_property_ui_text(prop, "Render", "Volume render settings for 3D viewport");
+ /* Velocity. */
+ prop = RNA_def_property(srna, "velocity_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "velocity_grid");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Volume_velocity_grid_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Velocity Grid",
+ "Name of the velocity field, or the base name if the velocity is split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "velocity_unit");
+ RNA_def_property_enum_items(prop, rna_enum_velocity_unit_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Velocity Unit",
+ "Define how the velocity vectors are interpreted with regard to time, 'frame' means "
+ "the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "velocity_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Velocity Scale", "Factor to control the amount of motion blur");
+
+ /* Scalar grids for velocity. */
+ prop = RNA_def_property(srna, "velocity_x_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_x_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity X Grid",
+ "Name of the grid for the X axis component of the velocity field if it "
+ "was split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_y_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_y_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity Y Grid",
+ "Name of the grid for the Y axis component of the velocity field if it "
+ "was split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_z_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_z_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity Z Grid",
+ "Name of the grid for the Z axis component of the velocity field if it "
+ "was split into multiple grids");
+
/* Common */
rna_def_animdata_common(srna);
}