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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2018-03-08 06:04:52 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-03-10 08:27:19 +0300
commitdb333d9ea4881d9f48e3cc4b1ec59b4dafb27cc0 (patch)
tree6ac02ba4a284e6196ed345be775cbad6436f5d7f /intern/cycles/render
parent78c2063685cb6e0d0bcb895cf4eb70686455d596 (diff)
Cycles: support arbitrary number of motion blur steps for objects.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/object.cpp167
-rw-r--r--intern/cycles/render/object.h10
-rw-r--r--intern/cycles/render/scene.cpp1
-rw-r--r--intern/cycles/render/scene.h1
-rw-r--r--intern/cycles/render/session.cpp2
5 files changed, 124 insertions, 57 deletions
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index bde340ae928..138de250c5f 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -54,6 +54,9 @@ struct UpdateObjectTransformState {
*/
map<Mesh*, float> surface_area_map;
+ /* Motion offsets for each object. */
+ array<uint> motion_offset;
+
/* Packed object arrays. Those will be filled in. */
uint *object_flag;
KernelObject *objects;
@@ -91,6 +94,7 @@ NODE_DEFINE(Object)
SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+ SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
@@ -103,46 +107,54 @@ Object::Object()
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
- motion.pre = transform_empty();
- motion.mid = transform_empty();
- motion.post = transform_empty();
- use_motion = false;
}
Object::~Object()
{
}
-void Object::compute_bounds(bool motion_blur)
+void Object::update_motion()
{
- BoundBox mbounds = mesh->bounds;
+ if(!use_motion()) {
+ return;
+ }
- if(motion_blur && use_motion) {
- MotionTransform mtfm = motion;
+ bool have_motion = false;
- if(hide_on_missing_motion) {
- /* Hide objects that have no valid previous or next transform, for
- * example particle that stop existing. TODO: add support for this
- * case in the kernel so we don't get render artifacts. */
- if(mtfm.pre == transform_empty() ||
- mtfm.post == transform_empty()) {
- bounds = BoundBox::empty;
+ for(size_t i = 0; i < motion.size(); i++) {
+ if(motion[i] == transform_empty()) {
+ if(hide_on_missing_motion) {
+ /* Hide objects that have no valid previous or next
+ * transform, for example particle that stop existing. It
+ * would be better to handle this in the kernel and make
+ * objects invisible outside certain motion steps. */
+ tfm = transform_empty();
+ motion.clear();
return;
}
+ else {
+ /* Otherwise just copy center motion. */
+ motion[i] = tfm;
+ }
}
- /* In case of missing motion information for previous/next frame,
- * assume there is no motion. */
- if(mtfm.pre == transform_empty()) {
- mtfm.pre = tfm;
- }
- if(mtfm.post == transform_empty()) {
- mtfm.post = tfm;
- }
- mtfm.mid = tfm;
+ /* Test if any of the transforms are actually different. */
+ have_motion = have_motion || motion[i] != tfm;
+ }
+
+ /* Clear motion array if there is no actual motion. */
+ if(!have_motion) {
+ motion.clear();
+ }
+}
+
+void Object::compute_bounds(bool motion_blur)
+{
+ BoundBox mbounds = mesh->bounds;
- DecomposedMotionTransform decomp;
- transform_motion_decompose(&decomp.pre, &mtfm.pre, 3);
+ if(motion_blur && use_motion()) {
+ array<DecomposedTransform> decomp(motion.size());
+ transform_motion_decompose(decomp.data(), motion.data(), motion.size());
bounds = BoundBox::empty;
@@ -152,11 +164,12 @@ void Object::compute_bounds(bool motion_blur)
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
Transform ttfm;
- transform_motion_array_interpolate(&ttfm, &decomp.pre, 3, t);
+ transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
bounds.grow(mbounds.transformed(&ttfm));
}
}
else {
+ /* No motion blur case. */
if(mesh->transform_applied) {
bounds = mbounds;
}
@@ -276,6 +289,29 @@ void Object::tag_update(Scene *scene)
scene->object_manager->need_update = true;
}
+bool Object::use_motion() const
+{
+ return (motion.size() > 1);
+}
+
+float Object::motion_time(int step) const
+{
+ return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Object::motion_step(float time) const
+{
+ if(use_motion()) {
+ for(size_t step = 0; step < motion.size(); step++) {
+ if(time == motion_time(step)) {
+ return step;
+ }
+ }
+ }
+
+ return -1;
+}
+
bool Object::is_traceable() const
{
/* Mesh itself can be empty,can skip all such objects. */
@@ -381,12 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
}
- memcpy(&kobject.tfm.pre, &tfm, sizeof(tfm));
- memcpy(&kobject.tfm.mid, &itfm, sizeof(itfm));
+ kobject.tfm = tfm;
+ kobject.itfm = itfm;
kobject.surface_area = surface_area;
kobject.pass_id = pass_id;
kobject.random_number = random_number;
kobject.particle_index = particle_index;
+ kobject.motion_offset = 0;
if(mesh->use_motion_blur) {
state->have_motion = true;
@@ -396,38 +433,39 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
if(state->need_motion == Scene::MOTION_PASS) {
- /* Motion transformations, is world/object space depending if mesh
- * comes with deformed position in object space, or if we transform
- * the shading point in world space.
- */
- MotionTransform mtfm = ob->motion;
-
- /* In case of missing motion information for previous/next frame,
- * assume there is no motion. */
- if(!ob->use_motion || mtfm.pre == transform_empty()) {
- mtfm.pre = ob->tfm;
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
+
+ /* Compute motion transforms. */
+ Transform tfm_pre, tfm_post;
+ if(ob->use_motion()) {
+ tfm_pre = ob->motion[0];
+ tfm_post = ob->motion[ob->motion.size() - 1];
}
- if(!ob->use_motion || mtfm.post == transform_empty()) {
- mtfm.post = ob->tfm;
+ else {
+ tfm_pre = tfm;
+ tfm_post = tfm;
}
+ /* Motion transformations, is world/object space depending if mesh
+ * comes with deformed position in object space, or if we transform
+ * the shading point in world space. */
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- mtfm.pre = mtfm.pre * itfm;
- mtfm.post = mtfm.post * itfm;
+ tfm_pre = tfm_pre * itfm;
+ tfm_post = tfm_post * itfm;
}
- object_motion_pass[object_index*OBJECT_MOTION_PASS_SIZE+0] = mtfm.pre;
- object_motion_pass[object_index*OBJECT_MOTION_PASS_SIZE+1] = mtfm.post;
+ int motion_pass_offset = object_index*OBJECT_MOTION_PASS_SIZE;
+ object_motion_pass[motion_pass_offset + 0] = tfm_pre;
+ object_motion_pass[motion_pass_offset + 1] = tfm_post;
}
else if(state->need_motion == Scene::MOTION_BLUR) {
- if(ob->use_motion) {
- /* decompose transformations for interpolation. */
- DecomposedMotionTransform decomp;
- MotionTransform mtfm = ob->motion;
- mtfm.mid = tfm;
-
- transform_motion_decompose(&decomp.pre, &mtfm.pre, 3);
- kobject.tfm = decomp;
+ if(ob->use_motion()) {
+ kobject.motion_offset = state->motion_offset[object_index];
+
+ /* Decompose transforms for interpolation. */
+ DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+ transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
flag |= SD_OBJECT_MOTION;
state->have_motion = true;
}
@@ -512,11 +550,28 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
state.objects = dscene->objects.alloc(scene->objects.size());
state.object_flag = dscene->object_flag.alloc(scene->objects.size());
+ state.object_motion = NULL;
state.object_motion_pass = NULL;
if(state.need_motion == Scene::MOTION_PASS) {
state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size());
}
+ else if(state.need_motion == Scene::MOTION_BLUR) {
+ /* Set object offsets into global object motion array. */
+ uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
+ uint motion_offset = 0;
+
+ foreach(Object *ob, scene->objects) {
+ *motion_offsets = motion_offset;
+ motion_offsets++;
+
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
+ motion_offset += ob->motion.size();
+ }
+
+ state.object_motion = dscene->object_motion.alloc(motion_offset);
+ }
/* Particle system device offsets
* 0 is dummy particle, index starts at 1.
@@ -560,6 +615,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
if(state.need_motion == Scene::MOTION_PASS) {
dscene->object_motion_pass.copy_to_device();
}
+ else if(state.need_motion == Scene::MOTION_BLUR) {
+ dscene->object_motion.copy_to_device();
+ }
dscene->data.bvh.have_motion = state.have_motion;
dscene->data.bvh.have_curves = state.have_curves;
@@ -709,6 +767,7 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene)
{
dscene->objects.free();
dscene->object_motion_pass.free();
+ dscene->object_motion.free();
dscene->object_flag.free();
}
@@ -748,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
!object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
{
- if(!(motion_blur && object->use_motion)) {
+ if(!(motion_blur && object->use_motion())) {
if(!object->mesh->transform_applied) {
object->apply_transform(apply_to_motion);
object->mesh->transform_applied = true;
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 7cf1528c4a7..c7212ae25f9 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -50,8 +50,7 @@ public:
int pass_id;
vector<ParamValue> attributes;
uint visibility;
- MotionTransform motion;
- bool use_motion;
+ array<Transform> motion;
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
@@ -70,6 +69,13 @@ public:
void compute_bounds(bool motion_blur);
void apply_transform(bool apply_to_motion);
+ /* Convert between normalized -1..1 motion time and index
+ * in the motion array. */
+ bool use_motion() const;
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+ void update_motion();
+
/* Check whether object is traceable and it worth adding it to
* kernel scene.
*/
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 6fc6e453aff..ba47e3ab6f8 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -61,6 +61,7 @@ DeviceScene::DeviceScene(Device *device)
patches(device, "__patches", MEM_TEXTURE),
objects(device, "__objects", MEM_TEXTURE),
object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE),
+ object_motion(device, "__object_motion", MEM_TEXTURE),
object_flag(device, "__object_flag", MEM_TEXTURE),
camera_motion(device, "__camera_motion", MEM_TEXTURE),
attributes_map(device, "__attributes_map", MEM_TEXTURE),
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 74e1df2f1d2..04bd4735a86 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -88,6 +88,7 @@ public:
/* objects */
device_vector<KernelObject> objects;
device_vector<Transform> object_motion_pass;
+ device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
/* cameras */
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 5732faf2a36..41156038558 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -662,7 +662,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
if(mesh->num_curves()) {
requested_features.use_hair = true;
}
- requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
+ requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur;
requested_features.use_camera_motion |= mesh->use_motion_blur;
#ifdef WITH_OPENSUBDIV
if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {