Cycles: support rendering PointCloud motion blur from attribute
This adds support to render PointCloud motion blur from a standard "velocity" attribute. This implementation is similar to that of the Mesh geometry, and perhaps some code could be deduplicated through a more generic API. `mesh_need_motion_attribute` was renamed `object_need_motion_attribute` as it does not really require a mesh and moved to `util.h` so that it can be shared. This fixes T94622. Reviewed By: brecht Maniphest Tasks: T94622 Differential Revision: https://developer.blender.org/D13719
This commit is contained in:
parent
b1bd0f8ffd
commit
4c3f52e7dc
Notes:
blender-bot
2023-02-14 08:35:51 +01:00
Referenced by issue #94622, Pointcloud with velocity attribute set using geometry nodes does not render with motion blur
|
@ -1086,40 +1086,6 @@ static void create_subd_mesh(Scene *scene,
|
|||
|
||||
/* Sync */
|
||||
|
||||
/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
|
||||
* things like velocity from cache modifier, fluid simulation).
|
||||
*
|
||||
* NOTE: This code is run prior to object motion blur initialization. so can not access properties
|
||||
* set by `sync_object_motion_init()`. */
|
||||
static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
{
|
||||
const Scene::MotionType need_motion = scene->need_motion();
|
||||
if (need_motion == Scene::MOTION_NONE) {
|
||||
/* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
|
||||
* attributes. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (need_motion == Scene::MOTION_BLUR) {
|
||||
/* A bit tricky and implicit case:
|
||||
* - Motion blur is enabled in the scene, which implies specific number of time steps for
|
||||
* objects.
|
||||
* - If the object has motion blur disabled on it, it will have 0 time steps.
|
||||
* - Motion attribute expects non-zero time steps.
|
||||
*
|
||||
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
|
||||
const bool use_motion = get_boolean(cobject, "use_motion_blur");
|
||||
if (!use_motion) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
|
||||
* level. */
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
|
||||
{
|
||||
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
|
||||
|
@ -1144,7 +1110,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
|
|||
|
||||
if (b_mesh) {
|
||||
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
|
||||
const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
|
||||
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()) :
|
||||
|
|
|
@ -37,12 +37,52 @@ static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
|
|||
}
|
||||
}
|
||||
|
||||
static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud)
|
||||
static void attr_create_motion(PointCloud *pointcloud,
|
||||
BL::Attribute &b_attribute,
|
||||
const float motion_scale)
|
||||
{
|
||||
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
|
||||
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
|
||||
const int num_points = pointcloud->get_points().size();
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &pointcloud->get_points()[0];
|
||||
Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
const float relative_time = motion_times[step] * 0.5f * motion_scale;
|
||||
float3 *mP = attr_mP->data_float3() + step * num_points;
|
||||
|
||||
for (int i = 0; i < num_points; i++) {
|
||||
mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_attributes(PointCloud *pointcloud,
|
||||
BL::PointCloud b_pointcloud,
|
||||
const bool need_motion,
|
||||
const float motion_scale)
|
||||
{
|
||||
AttributeSet &attributes = pointcloud->attributes;
|
||||
static const ustring u_velocity("velocity");
|
||||
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
|
||||
const ustring name{b_attribute.name().c_str()};
|
||||
|
||||
if (need_motion && name == u_velocity) {
|
||||
attr_create_motion(pointcloud, b_attribute, motion_scale);
|
||||
}
|
||||
|
||||
if (attributes.find(name)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -111,7 +151,11 @@ static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud)
|
|||
}
|
||||
}
|
||||
|
||||
static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud)
|
||||
static void export_pointcloud(Scene *scene,
|
||||
PointCloud *pointcloud,
|
||||
BL::PointCloud b_pointcloud,
|
||||
const bool need_motion,
|
||||
const float motion_scale)
|
||||
{
|
||||
/* TODO: optimize so we can straight memcpy arrays from Blender? */
|
||||
|
||||
|
@ -141,7 +185,7 @@ static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointClo
|
|||
}
|
||||
|
||||
/* Export attributes */
|
||||
copy_attributes(pointcloud, b_pointcloud);
|
||||
copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
|
||||
}
|
||||
|
||||
static void export_pointcloud_motion(PointCloud *pointcloud,
|
||||
|
@ -193,7 +237,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
|
|||
}
|
||||
|
||||
/* Export attributes */
|
||||
copy_attributes(pointcloud, b_pointcloud);
|
||||
copy_attributes(pointcloud, b_pointcloud, false, 0.0f);
|
||||
}
|
||||
|
||||
void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
|
||||
|
@ -207,7 +251,13 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
|
|||
|
||||
/* TODO: add option to filter out points in the view layer. */
|
||||
BL::PointCloud b_pointcloud(b_ob_info.object_data);
|
||||
export_pointcloud(scene, &new_pointcloud, b_pointcloud);
|
||||
/* 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;
|
||||
export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale);
|
||||
|
||||
/* update original sockets */
|
||||
for (const SocketType &socket : new_pointcloud.type->inputs) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define __BLENDER_UTIL_H__
|
||||
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
#include "util/algorithm.h"
|
||||
#include "util/array.h"
|
||||
|
@ -670,6 +671,40 @@ static inline uint object_ray_visibility(BL::Object &b_ob)
|
|||
return flag;
|
||||
}
|
||||
|
||||
/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
|
||||
* things like velocity from cache modifier, fluid simulation).
|
||||
*
|
||||
* NOTE: This code is run prior to object motion blur initialization. so can not access properties
|
||||
* set by `sync_object_motion_init()`. */
|
||||
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
{
|
||||
const Scene::MotionType need_motion = scene->need_motion();
|
||||
if (need_motion == Scene::MOTION_NONE) {
|
||||
/* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
|
||||
* attributes. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (need_motion == Scene::MOTION_BLUR) {
|
||||
/* A bit tricky and implicit case:
|
||||
* - Motion blur is enabled in the scene, which implies specific number of time steps for
|
||||
* objects.
|
||||
* - If the object has motion blur disabled on it, it will have 0 time steps.
|
||||
* - Motion attribute expects non-zero time steps.
|
||||
*
|
||||
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
|
||||
const bool use_motion = get_boolean(cobject, "use_motion_blur");
|
||||
if (!use_motion) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
|
||||
* level. */
|
||||
return true;
|
||||
}
|
||||
|
||||
class EdgeMap {
|
||||
public:
|
||||
EdgeMap()
|
||||
|
|
Loading…
Reference in New Issue