2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-05-24 13:36:13 +02:00
|
|
|
#include "blender/light_linking.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "blender/object_cull.h"
|
|
|
|
|
#include "blender/sync.h"
|
|
|
|
|
#include "blender/util.h"
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/alembic.h"
|
|
|
|
|
#include "scene/camera.h"
|
|
|
|
|
#include "scene/integrator.h"
|
|
|
|
|
#include "scene/light.h"
|
|
|
|
|
#include "scene/mesh.h"
|
|
|
|
|
#include "scene/object.h"
|
|
|
|
|
#include "scene/particles.h"
|
|
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/shader.h"
|
|
|
|
|
#include "scene/shader_graph.h"
|
|
|
|
|
#include "scene/shader_nodes.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/hash.h"
|
|
|
|
|
#include "util/log.h"
|
|
|
|
|
#include "util/task.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-02-14 10:51:40 -05:00
|
|
|
#include "BKE_duplilist.hh"
|
2022-09-30 18:54:26 +03:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
/* Utilities */
|
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* test if we can instance or if the object is modified */
|
2014-02-21 15:03:24 +01:00
|
|
|
if (b_ob.type() == BL::Object::type_META) {
|
|
|
|
|
/* multi-user and dupli metaballs are fused, can't instance */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
|
2011-04-27 11:58:34 +00:00
|
|
|
/* modifiers */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
|
|
|
|
|
/* object level material links */
|
|
|
|
|
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
|
|
|
|
|
if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
|
|
|
|
|
return true;
|
2021-01-25 16:20:10 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 13:38:07 +01:00
|
|
|
bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2021-11-10 13:38:07 +01:00
|
|
|
BL::ID b_ob_data = b_ob_info.object_data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-09-29 03:56:14 +02:00
|
|
|
if (!b_ob_data) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-10 13:38:07 +01:00
|
|
|
BL::Object::type_enum type = b_ob_info.iter_object.type();
|
2020-03-17 16:52:14 +01:00
|
|
|
|
Curves: Rename "Hair" types, variables, and functions to "Curves"
Based on discussions from T95355 and T94193, the plan is to use
the name "Curves" to describe the data-block container for multiple
curves. Eventually this will replace the existing "Curve" data-block.
However, it will be a while before the curve data-block can be replaced
so in order to distinguish the two curve types in the UI, "Hair Curves"
will be used, but eventually changed back to "Curves".
This patch renames "hair-related" files, functions, types, and variable
names to this convention. A deep rename is preferred to keep code
consistent and to avoid any "hair" terminology from leaking, since the
new data-block is meant for all curve types, not just hair use cases.
The downside of this naming is that the difference between "Curve"
and "Curves" has become important. That was considered during
design discussons and deemed acceptable, especially given the
non-permanent nature of the somewhat common conflict.
Some points of interest:
- All DNA compatibility is lost, just like rBf59767ff9729.
- I renamed `ID_HA` to `ID_CV` so there is no complete mismatch.
- `hair_curves` is used where necessary to distinguish from the
existing "curves" plural.
- I didn't rename any of the cycles/rendering code function names,
since that is also used by the old hair particle system.
Differential Revision: https://developer.blender.org/D14007
2022-02-07 11:55:54 -06:00
|
|
|
if (type == BL::Object::type_VOLUME || type == BL::Object::type_CURVES ||
|
2021-12-01 17:30:46 +01:00
|
|
|
type == BL::Object::type_POINTCLOUD)
|
|
|
|
|
{
|
2020-03-17 16:52:14 +01:00
|
|
|
/* Will be exported attached to mesh. */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-05 11:51:34 -05:00
|
|
|
return b_ob_data.is_a(&RNA_Mesh);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-10 13:38:07 +01:00
|
|
|
bool BlenderSync::object_can_have_geometry(BL::Object &b_ob)
|
|
|
|
|
{
|
|
|
|
|
BL::Object::type_enum type = b_ob.type();
|
|
|
|
|
switch (type) {
|
|
|
|
|
case BL::Object::type_MESH:
|
|
|
|
|
case BL::Object::type_CURVE:
|
|
|
|
|
case BL::Object::type_SURFACE:
|
|
|
|
|
case BL::Object::type_META:
|
|
|
|
|
case BL::Object::type_FONT:
|
Curves: Rename "Hair" types, variables, and functions to "Curves"
Based on discussions from T95355 and T94193, the plan is to use
the name "Curves" to describe the data-block container for multiple
curves. Eventually this will replace the existing "Curve" data-block.
However, it will be a while before the curve data-block can be replaced
so in order to distinguish the two curve types in the UI, "Hair Curves"
will be used, but eventually changed back to "Curves".
This patch renames "hair-related" files, functions, types, and variable
names to this convention. A deep rename is preferred to keep code
consistent and to avoid any "hair" terminology from leaking, since the
new data-block is meant for all curve types, not just hair use cases.
The downside of this naming is that the difference between "Curve"
and "Curves" has become important. That was considered during
design discussons and deemed acceptable, especially given the
non-permanent nature of the somewhat common conflict.
Some points of interest:
- All DNA compatibility is lost, just like rBf59767ff9729.
- I renamed `ID_HA` to `ID_CV` so there is no complete mismatch.
- `hair_curves` is used where necessary to distinguish from the
existing "curves" plural.
- I didn't rename any of the cycles/rendering code function names,
since that is also used by the old hair particle system.
Differential Revision: https://developer.blender.org/D14007
2022-02-07 11:55:54 -06:00
|
|
|
case BL::Object::type_CURVES:
|
2021-11-10 13:38:07 +01:00
|
|
|
case BL::Object::type_POINTCLOUD:
|
|
|
|
|
case BL::Object::type_VOLUME:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
bool BlenderSync::object_is_light(BL::Object &b_ob)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
BL::ID b_ob_data = b_ob.data();
|
|
|
|
|
|
2018-06-27 14:41:53 +02:00
|
|
|
return (b_ob_data && b_ob_data.is_a(&RNA_Light));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Attribute Node: support accessing attributes of View Layer and Scene.
The attribute node already allows accessing attributes associated
with objects and meshes, which allows changing the behavior of the
same material between different objects or instances. The same idea
can be extended to an even more global level of layers and scenes.
Currently view layers provide an option to replace all materials
with a different one. However, since the same material will be applied
to all objects in the layer, varying the behavior between layers while
preserving distinct materials requires duplicating objects.
Providing access to properties of layers and scenes via the attribute
node enables making materials with built-in switches or settings that
can be controlled globally at the view layer level. This is probably
most useful for complex NPR shading and compositing. Like with objects,
the node can also access built-in scene properties, like render resolution
or FOV of the active camera. Lookup is also attempted in World, similar
to how the Object mode checks the Mesh datablock.
In Cycles this mode is implemented by replacing the attribute node with
the attribute value during sync, allowing constant folding to take the
values into account. This means however that materials that use this
feature have to be re-synced upon any changes to scene, world or camera.
The Eevee version uses a new uniform buffer containing a sorted array
mapping name hashes to values, with binary search lookup. The array
is limited to 512 entries, which is effectively limitless even
considering it is shared by all materials in the scene; it is also
just 16KB of memory so no point trying to optimize further.
The buffer has to be rebuilt when new attributes are detected in a
material, so the draw engine keeps a table of recently seen attribute
names to minimize the chance of extra rebuilds mid-draw.
Differential Revision: https://developer.blender.org/D15941
2022-09-12 00:30:58 +03:00
|
|
|
bool BlenderSync::object_is_camera(BL::Object &b_ob)
|
|
|
|
|
{
|
|
|
|
|
BL::ID b_ob_data = b_ob.data();
|
|
|
|
|
|
|
|
|
|
return (b_ob_data && b_ob_data.is_a(&RNA_Camera));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 14:22:40 +02:00
|
|
|
void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize motion blur for object, detecting if it's enabled and creating motion
|
|
|
|
|
* steps array if so. */
|
|
|
|
|
array<Transform> motion;
|
|
|
|
|
object->set_motion(motion);
|
|
|
|
|
|
2021-10-08 13:45:34 +02:00
|
|
|
Geometry *geom = object->get_geometry();
|
|
|
|
|
if (!geom) {
|
2021-05-11 14:22:40 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 15:56:31 +02:00
|
|
|
int motion_steps = 0;
|
|
|
|
|
bool use_motion_blur = false;
|
2021-05-11 14:22:40 +02:00
|
|
|
|
2021-10-08 13:45:34 +02:00
|
|
|
Scene::MotionType need_motion = scene->need_motion();
|
2021-05-11 14:22:40 +02:00
|
|
|
if (need_motion == Scene::MOTION_BLUR) {
|
|
|
|
|
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
|
|
|
|
|
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
|
2021-07-12 15:56:31 +02:00
|
|
|
use_motion_blur = true;
|
2021-05-11 14:22:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-08 13:45:34 +02:00
|
|
|
else if (need_motion != Scene::MOTION_NONE) {
|
2021-05-11 14:22:40 +02:00
|
|
|
motion_steps = 3;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 15:56:31 +02:00
|
|
|
geom->set_use_motion_blur(use_motion_blur);
|
2024-01-10 18:45:15 +01:00
|
|
|
|
|
|
|
|
if (!geom->has_motion_blur()) {
|
|
|
|
|
/* Only set motion steps if geometry doesn't already have
|
|
|
|
|
* motion blur from a velocity attribute. */
|
|
|
|
|
geom->set_motion_steps(motion_steps);
|
|
|
|
|
}
|
2021-07-12 15:56:31 +02:00
|
|
|
|
2021-05-11 14:22:40 +02:00
|
|
|
motion.resize(motion_steps, transform_empty());
|
|
|
|
|
|
|
|
|
|
if (motion_steps) {
|
|
|
|
|
motion[motion_steps / 2] = object->get_tfm();
|
|
|
|
|
|
|
|
|
|
/* update motion socket before trying to access object->motion_time */
|
|
|
|
|
object->set_motion(motion);
|
|
|
|
|
|
|
|
|
|
for (size_t step = 0; step < motion_steps; step++) {
|
|
|
|
|
motion_times.insert(object->motion_time(step));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2018-02-26 16:46:48 +01:00
|
|
|
Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
2018-07-25 12:26:09 +02:00
|
|
|
BL::ViewLayer &b_view_layer,
|
2018-05-30 15:21:21 +02:00
|
|
|
BL::DepsgraphObjectInstance &b_instance,
|
2015-04-10 18:09:58 +05:00
|
|
|
float motion_time,
|
2020-02-02 13:09:18 +01:00
|
|
|
bool use_particle_hair,
|
2019-08-27 15:47:30 +02:00
|
|
|
bool show_lights,
|
2016-11-13 00:45:16 +01:00
|
|
|
BlenderObjectCulling &culling,
|
2020-10-21 16:38:36 +02:00
|
|
|
bool *use_portal,
|
|
|
|
|
TaskPool *geom_task_pool)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2018-05-30 15:21:21 +02:00
|
|
|
const bool is_instance = b_instance.is_instance();
|
|
|
|
|
BL::Object b_ob = b_instance.object();
|
|
|
|
|
BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
|
2021-09-06 18:22:24 +02:00
|
|
|
BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
|
2017-06-06 13:58:40 +02:00
|
|
|
const bool motion = motion_time != 0.0f;
|
|
|
|
|
/*const*/ Transform tfm = get_transform(b_ob.matrix_world());
|
2024-12-26 17:53:55 +01:00
|
|
|
int *persistent_id = nullptr;
|
2017-06-06 13:58:40 +02:00
|
|
|
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
|
2017-06-06 16:27:02 +02:00
|
|
|
if (is_instance) {
|
2018-05-30 15:21:21 +02:00
|
|
|
persistent_id_array = b_instance.persistent_id();
|
2017-06-06 13:58:40 +02:00
|
|
|
persistent_id = persistent_id_array.data;
|
2021-11-04 18:32:01 +01:00
|
|
|
if (!b_ob_info.is_real_object_data()) {
|
|
|
|
|
/* Remember which object data the geometry is coming from, so that we can sync it when the
|
|
|
|
|
* object has changed. */
|
|
|
|
|
instance_geometries_by_object[b_ob_info.real_object.ptr.data].insert(b_ob_info.object_data);
|
|
|
|
|
}
|
2017-06-06 13:58:40 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* light is handled separately */
|
2018-07-25 12:35:27 +02:00
|
|
|
if (!motion && object_is_light(b_ob)) {
|
2019-08-27 15:47:30 +02:00
|
|
|
if (!show_lights) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2019-08-27 15:47:30 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-25 12:35:27 +02:00
|
|
|
/* TODO: don't use lights for excluded layers used as mask layer,
|
|
|
|
|
* when dynamic overrides are back. */
|
|
|
|
|
#if 0
|
2019-04-17 08:16:53 +02:00
|
|
|
if (!((layer_flag & view_layer.holdout_layer) && (layer_flag & view_layer.exclude_layer)))
|
2018-07-25 12:35:27 +02:00
|
|
|
#endif
|
2017-06-06 16:27:02 +02:00
|
|
|
{
|
|
|
|
|
sync_light(b_parent,
|
|
|
|
|
persistent_id,
|
2021-09-06 18:22:24 +02:00
|
|
|
b_ob_info,
|
2018-05-30 15:21:21 +02:00
|
|
|
is_instance ? b_instance.random_id() : 0,
|
2017-06-06 16:27:02 +02:00
|
|
|
tfm,
|
|
|
|
|
use_portal);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-12-01 17:30:46 +01:00
|
|
|
/* only interested in object that we can create geometry from */
|
2021-11-10 13:38:07 +01:00
|
|
|
if (!object_is_geometry(b_ob_info)) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2016-11-13 00:45:16 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-13 00:16:50 +01:00
|
|
|
/* Perform object culling. */
|
2016-11-13 00:45:16 +01:00
|
|
|
if (culling.test(scene, b_ob, tfm)) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2015-04-10 18:09:58 +05:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-09-29 03:56:14 +02:00
|
|
|
/* Visibility flags for both parent and child. */
|
2017-11-18 06:06:27 +01:00
|
|
|
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
2021-08-04 19:43:40 +02:00
|
|
|
bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
|
2017-09-29 03:56:14 +02:00
|
|
|
uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-09-29 03:56:14 +02:00
|
|
|
if (b_parent.ptr.data != b_ob.ptr.data) {
|
|
|
|
|
visibility &= object_ray_visibility(b_parent);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-25 12:35:27 +02:00
|
|
|
/* TODO: make holdout objects on excluded layer invisible for non-camera rays. */
|
|
|
|
|
#if 0
|
2019-04-17 08:16:53 +02:00
|
|
|
if (use_holdout && (layer_flag & view_layer.exclude_layer)) {
|
2017-09-29 03:56:14 +02:00
|
|
|
visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
|
|
|
|
|
}
|
2018-07-25 12:35:27 +02:00
|
|
|
#endif
|
2017-09-29 03:56:14 +02:00
|
|
|
|
2018-07-25 12:26:09 +02:00
|
|
|
/* Clear camera visibility for indirect only objects. */
|
2019-07-04 17:28:39 +02:00
|
|
|
bool use_indirect_only = !use_holdout &&
|
|
|
|
|
b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer);
|
2018-07-25 12:26:09 +02:00
|
|
|
if (use_indirect_only) {
|
2017-09-29 03:56:14 +02:00
|
|
|
visibility &= ~PATH_RAY_CAMERA;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-09-29 03:56:14 +02:00
|
|
|
/* Don't export completely invisible objects. */
|
|
|
|
|
if (visibility == 0) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2017-09-29 03:56:14 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 16:38:36 +02:00
|
|
|
/* Use task pool only for non-instances, since sync_dupli_particle accesses
|
|
|
|
|
* geometry. This restriction should be removed for better performance. */
|
2024-12-26 17:53:55 +01:00
|
|
|
TaskPool *object_geom_task_pool = (is_instance) ? nullptr : geom_task_pool;
|
2020-10-21 16:38:36 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
/* key to lookup object */
|
2021-09-06 18:22:24 +02:00
|
|
|
ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
|
2011-04-27 11:58:34 +00:00
|
|
|
Object *object;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
/* motion vector case */
|
|
|
|
|
if (motion) {
|
|
|
|
|
object = object_map.find(key);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-08 04:04:52 +01:00
|
|
|
if (object && object->use_motion()) {
|
|
|
|
|
/* Set transform at matching motion time step. */
|
|
|
|
|
int time_index = object->motion_step(motion_time);
|
|
|
|
|
if (time_index >= 0) {
|
2020-11-04 11:17:38 +01:00
|
|
|
array<Transform> motion = object->get_motion();
|
|
|
|
|
motion[time_index] = tfm;
|
|
|
|
|
object->set_motion(motion);
|
2016-08-07 22:41:35 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* mesh deformation */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (object->get_geometry()) {
|
2021-09-06 18:22:24 +02:00
|
|
|
sync_geometry_motion(
|
|
|
|
|
b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-08 16:35:28 +00:00
|
|
|
return object;
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
/* test if we need to sync */
|
2021-05-17 15:43:42 +02:00
|
|
|
bool object_updated = object_map.add_or_update(&object, b_ob, b_parent, key) ||
|
|
|
|
|
(tfm != object->get_tfm());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-11-12 14:29:52 +00:00
|
|
|
/* mesh sync */
|
2021-09-06 18:22:24 +02:00
|
|
|
Geometry *geometry = sync_geometry(
|
|
|
|
|
b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_geometry(geometry);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-26 20:34:29 +01:00
|
|
|
/* special case not tracked by object update flags */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
if (sync_object_attributes(b_instance, object)) {
|
|
|
|
|
object_updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-26 20:34:29 +01:00
|
|
|
/* holdout */
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_use_holdout(use_holdout);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_visibility(visibility);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-11 16:26:20 +01:00
|
|
|
object->set_is_shadow_catcher(b_ob.is_shadow_catcher() || b_parent.is_shadow_catcher());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-28 13:54:18 +02:00
|
|
|
float shadow_terminator_shading_offset = get_float(cobject, "shadow_terminator_offset");
|
|
|
|
|
object->set_shadow_terminator_shading_offset(shadow_terminator_shading_offset);
|
|
|
|
|
|
|
|
|
|
float shadow_terminator_geometry_offset = get_float(cobject,
|
|
|
|
|
"shadow_terminator_geometry_offset");
|
|
|
|
|
object->set_shadow_terminator_geometry_offset(shadow_terminator_geometry_offset);
|
2020-05-05 13:55:24 +02:00
|
|
|
|
2021-08-03 12:20:28 +02:00
|
|
|
float ao_distance = get_float(cobject, "ao_distance");
|
|
|
|
|
if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
|
|
|
|
|
PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
|
|
|
|
|
ao_distance = get_float(cparent, "ao_distance");
|
|
|
|
|
}
|
|
|
|
|
object->set_ao_distance(ao_distance);
|
|
|
|
|
|
Cycles: approximate shadow caustics using manifold next event estimation
This adds support for selective rendering of caustics in shadows of refractive
objects. Example uses are rendering of underwater caustics and eye caustics.
This is based on "Manifold Next Event Estimation", a method developed for
production rendering. The idea is to selectively enable shadow caustics on a
few objects in the scene where they have a big visual impact, without impacting
render performance for the rest of the scene.
The Shadow Caustic option must be manually enabled on light, caustic receiver
and caster objects. For such light paths, the Filter Glossy option will be
ignored and replaced by sharp caustics.
Currently this method has a various limitations:
* Only caustics in shadows of refractive objects work, which means no caustics
from reflection or caustics that outside shadows. Only up to 4 refractive
caustic bounces are supported.
* Caustic caster objects should have smooth normals.
* Not currently support for Metal GPU rendering.
In the future this method may be extended for more general caustics.
TECHNICAL DETAILS
This code adds manifold next event estimation through refractive surface(s) as a
new sampling technique for direct lighting, i.e. finding the point on the
refractive surface(s) along the path to a light sample, which satisfies Fermat's
principle for a given microfacet normal and the path's end points. This
technique involves walking on the "specular manifold" using a pseudo newton
solver. Such a manifold is defined by the specular constraint matrix from the
manifold exploration framework [2]. For each refractive interface, this
constraint is defined by enforcing that the generalized half-vector projection
onto the interface local tangent plane is null. The newton solver guides the
walk by linearizing the manifold locally before reprojecting the linear solution
onto the refractive surface. See paper [1] for more details about the technique
itself and [3] for the half-vector light transport formulation, from which it is
derived.
[1] Manifold Next Event Estimation
Johannes Hanika, Marc Droske, and Luca Fascione. 2015.
Comput. Graph. Forum 34, 4 (July 2015), 87–97.
https://jo.dreggn.org/home/2015_mnee.pdf
[2] Manifold exploration: a Markov Chain Monte Carlo technique for rendering
scenes with difficult specular transport Wenzel Jakob and Steve Marschner.
2012. ACM Trans. Graph. 31, 4, Article 58 (July 2012), 13 pages.
https://www.cs.cornell.edu/projects/manifolds-sg12/
[3] The Natural-Constraint Representation of the Path Space for Efficient
Light Transport Simulation. Anton S. Kaplanyan, Johannes Hanika, and Carsten
Dachsbacher. 2014. ACM Trans. Graph. 33, 4, Article 102 (July 2014), 13 pages.
https://cg.ivd.kit.edu/english/HSLT.php
The code for this samping technique was inserted at the light sampling stage
(direct lighting). If the walk is successful, it turns off path regularization
using a specialized flag in the path state (PATH_MNEE_SUCCESS). This flag tells
the integrator not to blur the brdf roughness further down the path (in a child
ray created from BSDF sampling). In addition, using a cascading mechanism of
flag values, we cull connections to caustic lights for this and children rays,
which should be resolved through MNEE.
This mechanism also cancels the MIS bsdf counter part at the casutic receiver
depth, in essence leaving MNEE as the only sampling technique from receivers
through refractive casters to caustic lights. This choice might not be optimal
when the light gets large wrt to the receiver, though this is usually not when
you want to use MNEE.
This connection culling strategy removes a fair amount of fireflies, at the cost
of introducing a slight bias. Because of the selective nature of the culling
mechanism, reflective caustics still benefit from the native path
regularization, which further removes fireflies on other surfaces (bouncing
light off casters).
Differential Revision: https://developer.blender.org/D13533
2022-04-01 15:44:24 +02:00
|
|
|
bool is_caustics_caster = get_boolean(cobject, "is_caustics_caster");
|
|
|
|
|
object->set_is_caustics_caster(is_caustics_caster);
|
|
|
|
|
|
|
|
|
|
bool is_caustics_receiver = get_boolean(cobject, "is_caustics_receiver");
|
|
|
|
|
object->set_is_caustics_receiver(is_caustics_receiver);
|
|
|
|
|
|
2025-01-02 12:48:21 +01:00
|
|
|
object->set_is_bake_target(b_ob_info.real_object == b_bake_target);
|
|
|
|
|
|
2018-10-28 05:37:41 -04:00
|
|
|
/* sync the asset name for Cryptomatte */
|
|
|
|
|
BL::Object parent = b_ob.parent();
|
|
|
|
|
ustring parent_name;
|
|
|
|
|
if (parent) {
|
|
|
|
|
while (parent.parent()) {
|
|
|
|
|
parent = parent.parent();
|
|
|
|
|
}
|
|
|
|
|
parent_name = parent.name();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
parent_name = b_ob.name();
|
|
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_asset_name(parent_name);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-08 16:35:28 +00:00
|
|
|
/* object sync
|
|
|
|
|
* transform comparison should not be needed, but duplis don't work perfect
|
2012-09-03 13:18:23 +00:00
|
|
|
* in the depsgraph and may not signal changes, so this is a workaround */
|
2020-11-04 11:17:38 +01:00
|
|
|
if (object->is_modified() || object_updated ||
|
2021-05-17 15:43:42 +02:00
|
|
|
(object->get_geometry() && object->get_geometry()->is_modified()))
|
|
|
|
|
{
|
2011-10-03 17:42:24 +00:00
|
|
|
object->name = b_ob.name().c_str();
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_pass_id(b_ob.pass_index());
|
2022-03-07 17:34:52 +01:00
|
|
|
const BL::Array<float, 4> object_color = b_ob.color();
|
|
|
|
|
object->set_color(get_float3(object_color));
|
|
|
|
|
object->set_alpha(object_color[3]);
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_tfm(tfm);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-14 18:13:44 +03:00
|
|
|
/* dupli texture coordinates and random_id */
|
2017-06-06 16:27:02 +02:00
|
|
|
if (is_instance) {
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
|
|
|
|
|
make_float3(0.5f, 0.5f, 0.5f));
|
|
|
|
|
object->set_dupli_uv(get_float2(b_instance.uv()));
|
|
|
|
|
object->set_random_id(b_instance.random_id());
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2021-02-17 01:47:18 +01:00
|
|
|
object->set_dupli_generated(zero_float3());
|
|
|
|
|
object->set_dupli_uv(zero_float2());
|
2020-11-04 11:17:38 +01:00
|
|
|
object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-24 13:36:13 +02:00
|
|
|
/* Light group and linking. */
|
2023-06-10 15:31:06 +02:00
|
|
|
string lightgroup = b_ob.lightgroup();
|
|
|
|
|
if (lightgroup.empty()) {
|
|
|
|
|
lightgroup = b_parent.lightgroup();
|
|
|
|
|
}
|
|
|
|
|
object->set_lightgroup(ustring(lightgroup));
|
2022-04-02 00:11:11 +02:00
|
|
|
|
2023-05-24 13:36:13 +02:00
|
|
|
object->set_light_set_membership(BlenderLightLink::get_light_set_membership(b_parent, b_ob));
|
|
|
|
|
object->set_receiver_light_set(BlenderLightLink::get_receiver_light_set(b_parent, b_ob));
|
|
|
|
|
object->set_shadow_set_membership(BlenderLightLink::get_shadow_set_membership(b_parent, b_ob));
|
|
|
|
|
object->set_blocker_shadow_set(BlenderLightLink::get_blocker_shadow_set(b_parent, b_ob));
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
object->tag_update(scene);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-05-11 14:22:40 +02:00
|
|
|
sync_object_motion_init(b_parent, b_ob, object);
|
|
|
|
|
|
2019-01-02 16:32:32 +01:00
|
|
|
if (is_instance) {
|
|
|
|
|
/* Sync possible particle data. */
|
|
|
|
|
sync_dupli_particle(b_parent, b_instance, object);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-08 16:35:28 +00:00
|
|
|
return object;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-30 18:54:26 +03:00
|
|
|
extern "C" DupliObject *rna_hack_DepsgraphObjectInstance_dupli_object_get(PointerRNA *ptr);
|
2020-12-23 15:45:55 +01:00
|
|
|
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
|
|
|
|
|
const string &name,
|
|
|
|
|
bool use_instancer)
|
|
|
|
|
{
|
2022-09-30 18:54:26 +03:00
|
|
|
::Object *ob = (::Object *)b_instance.object().ptr.data;
|
|
|
|
|
::DupliObject *dupli = nullptr;
|
|
|
|
|
::Object *dupli_parent = nullptr;
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
|
|
|
|
|
/* If requesting instance data, check the parent particle system and object. */
|
|
|
|
|
if (use_instancer && b_instance.is_instance()) {
|
2022-09-30 18:54:26 +03:00
|
|
|
dupli = rna_hack_DepsgraphObjectInstance_dupli_object_get(&b_instance.ptr);
|
|
|
|
|
dupli_parent = (::Object *)b_instance.parent().ptr.data;
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
}
|
|
|
|
|
|
2022-09-30 18:54:26 +03:00
|
|
|
float4 value;
|
|
|
|
|
BKE_object_dupli_find_rgba_attribute(ob, dupli, dupli_parent, name.c_str(), &value.x);
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
|
2022-09-30 18:54:26 +03:00
|
|
|
return value;
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
|
|
|
|
|
{
|
|
|
|
|
/* Find which attributes are needed. */
|
2020-11-04 11:17:38 +01:00
|
|
|
AttributeRequestSet requests = object->get_geometry()->needed_attributes();
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
|
|
|
|
|
/* Delete attributes that became unnecessary. */
|
|
|
|
|
vector<ParamValue> &attributes = object->attributes;
|
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
|
|
for (int i = attributes.size() - 1; i >= 0; i--) {
|
|
|
|
|
if (!requests.find(attributes[i].name())) {
|
|
|
|
|
attributes.erase(attributes.begin() + i);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update attribute values. */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (AttributeRequest &req : requests.requests) {
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
ustring name = req.name;
|
|
|
|
|
|
|
|
|
|
std::string real_name;
|
|
|
|
|
BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
|
|
|
|
|
|
Attribute Node: support accessing attributes of View Layer and Scene.
The attribute node already allows accessing attributes associated
with objects and meshes, which allows changing the behavior of the
same material between different objects or instances. The same idea
can be extended to an even more global level of layers and scenes.
Currently view layers provide an option to replace all materials
with a different one. However, since the same material will be applied
to all objects in the layer, varying the behavior between layers while
preserving distinct materials requires duplicating objects.
Providing access to properties of layers and scenes via the attribute
node enables making materials with built-in switches or settings that
can be controlled globally at the view layer level. This is probably
most useful for complex NPR shading and compositing. Like with objects,
the node can also access built-in scene properties, like render resolution
or FOV of the active camera. Lookup is also attempted in World, similar
to how the Object mode checks the Mesh datablock.
In Cycles this mode is implemented by replacing the attribute node with
the attribute value during sync, allowing constant folding to take the
values into account. This means however that materials that use this
feature have to be re-synced upon any changes to scene, world or camera.
The Eevee version uses a new uniform buffer containing a sorted array
mapping name hashes to values, with binary search lookup. The array
is limited to 512 entries, which is effectively limitless even
considering it is shared by all materials in the scene; it is also
just 16KB of memory so no point trying to optimize further.
The buffer has to be rebuilt when new attributes are detected in a
material, so the draw engine keeps a table of recently seen attribute
names to minimize the chance of extra rebuilds mid-draw.
Differential Revision: https://developer.blender.org/D15941
2022-09-12 00:30:58 +03:00
|
|
|
if (type == BL::ShaderNodeAttribute::attribute_type_OBJECT ||
|
|
|
|
|
type == BL::ShaderNodeAttribute::attribute_type_INSTANCER)
|
|
|
|
|
{
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
|
|
|
|
|
float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
|
|
|
|
|
|
|
|
|
|
/* Try finding the existing attribute value. */
|
2024-12-26 17:53:55 +01:00
|
|
|
ParamValue *param = nullptr;
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < attributes.size(); i++) {
|
|
|
|
|
if (attributes[i].name() == name) {
|
|
|
|
|
param = &attributes[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Replace or add the value. */
|
2024-10-17 19:48:38 +02:00
|
|
|
ParamValue new_param(name, TypeFloat4, 1, &value);
|
Materials: add custom object properties as uniform attributes.
This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.
In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.
The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.
In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.
This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.
The back-end Cycles code is already refactored and committed by Brecht.
Differential Revision: https://developer.blender.org/D2057
2020-08-05 19:14:40 +03:00
|
|
|
assert(new_param.datasize() == sizeof(value));
|
|
|
|
|
|
|
|
|
|
if (!param) {
|
|
|
|
|
changed = true;
|
|
|
|
|
attributes.push_back(new_param);
|
|
|
|
|
}
|
|
|
|
|
else if (memcmp(param->data(), &value, sizeof(value)) != 0) {
|
|
|
|
|
changed = true;
|
|
|
|
|
*param = new_param;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Object Loop */
|
|
|
|
|
|
2021-08-20 02:30:50 +02:00
|
|
|
void BlenderSync::sync_procedural(BL::Object &b_ob,
|
|
|
|
|
BL::MeshSequenceCacheModifier &b_mesh_cache,
|
|
|
|
|
bool has_subdivision_modifier)
|
2021-08-19 14:34:01 +02:00
|
|
|
{
|
|
|
|
|
#ifdef WITH_ALEMBIC
|
|
|
|
|
BL::CacheFile cache_file = b_mesh_cache.cache_file();
|
|
|
|
|
void *cache_file_key = cache_file.ptr.data;
|
|
|
|
|
|
|
|
|
|
AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
|
|
|
|
|
procedural_map.find(cache_file_key));
|
|
|
|
|
|
|
|
|
|
if (procedural == nullptr) {
|
|
|
|
|
procedural = scene->create_node<AlembicProcedural>();
|
|
|
|
|
procedural_map.add(cache_file_key, procedural);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
procedural_map.used(procedural);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-26 10:36:04 +02:00
|
|
|
float current_frame = static_cast<float>(b_scene.frame_current());
|
2021-08-19 14:34:01 +02:00
|
|
|
if (cache_file.override_frame()) {
|
|
|
|
|
current_frame = cache_file.frame();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cache_file.override_frame()) {
|
2021-08-26 10:36:04 +02:00
|
|
|
procedural->set_start_frame(static_cast<float>(b_scene.frame_start()));
|
|
|
|
|
procedural->set_end_frame(static_cast<float>(b_scene.frame_end()));
|
2021-08-19 14:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
procedural->set_frame(current_frame);
|
|
|
|
|
procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
|
|
|
|
|
procedural->set_frame_offset(cache_file.frame_offset());
|
|
|
|
|
|
|
|
|
|
string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
|
|
|
|
|
procedural->set_filepath(ustring(absolute_path));
|
|
|
|
|
|
Alembic: add support for reading override layers
Override layers are a standard feature of Alembic, where archives can override
data from other archives, provided that the hierarchies match.
This is useful for modifying a UV map, updating an animation, or even creating
some sort of LOD system where low resolution meshes are swapped by high resolution
versions.
It is possible to add UV maps and vertex colors using this system, however, they
will only appear in the spreadsheet editor when viewing evaluated data, as the UV
map and Vertex color UI only show data present on the original mesh.
Implementation wise, this adds a `CacheFileLayer` data structure to the `CacheFile`
DNA, as well as some operators and UI to present and manage the layers. For both
the Alembic importer and the Cycles procedural, the main change is creating an
archive from a list of filepaths, instead of a single one.
After importing the base file through the regular import operator, layers can be added
to or removed from the `CacheFile` via the UI list under the `Override Layers` panel
located in the Mesh Sequence Cache modifier. Layers can also be moved around or
hidden.
See differential page for tests files and demos.
Reviewed by: brecht, sybren
Differential Revision: https://developer.blender.org/D13603
2022-01-17 14:50:47 +01:00
|
|
|
array<ustring> layers;
|
|
|
|
|
for (BL::CacheFileLayer &layer : cache_file.layers) {
|
|
|
|
|
if (layer.hide_layer()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
absolute_path = blender_absolute_path(b_data, b_ob, layer.filepath());
|
|
|
|
|
layers.push_back_slow(ustring(absolute_path));
|
|
|
|
|
}
|
|
|
|
|
procedural->set_layers(layers);
|
|
|
|
|
|
2021-08-19 14:34:01 +02:00
|
|
|
procedural->set_scale(cache_file.scale());
|
|
|
|
|
|
2021-08-20 14:29:05 +02:00
|
|
|
procedural->set_use_prefetch(cache_file.use_prefetch());
|
|
|
|
|
procedural->set_prefetch_cache_size(cache_file.prefetch_cache_size());
|
|
|
|
|
|
2021-08-19 14:34:01 +02:00
|
|
|
/* create or update existing AlembicObjects */
|
|
|
|
|
ustring object_path = ustring(b_mesh_cache.object_path());
|
|
|
|
|
|
|
|
|
|
AlembicObject *abc_object = procedural->get_or_create_object(object_path);
|
|
|
|
|
|
|
|
|
|
array<Node *> used_shaders = find_used_shaders(b_ob);
|
|
|
|
|
abc_object->set_used_shaders(used_shaders);
|
|
|
|
|
|
|
|
|
|
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
|
|
|
|
const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
|
|
|
|
|
abc_object->set_subd_dicing_rate(subd_dicing_rate);
|
|
|
|
|
abc_object->set_subd_max_level(max_subdivisions);
|
|
|
|
|
|
2021-08-20 02:30:50 +02:00
|
|
|
abc_object->set_ignore_subdivision(!has_subdivision_modifier);
|
|
|
|
|
|
2021-08-19 14:34:01 +02:00
|
|
|
if (abc_object->is_modified() || procedural->is_modified()) {
|
|
|
|
|
procedural->tag_update(scene);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
(void)b_ob;
|
|
|
|
|
(void)b_mesh_cache;
|
2021-08-26 12:36:13 +10:00
|
|
|
(void)has_subdivision_modifier;
|
2021-08-19 14:34:01 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|
|
|
|
BL::SpaceView3D &b_v3d,
|
|
|
|
|
float motion_time)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2020-10-21 16:38:36 +02:00
|
|
|
/* Task pool for multithreaded geometry sync. */
|
|
|
|
|
TaskPool geom_task_pool;
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* layer data */
|
2014-03-29 13:03:46 +01:00
|
|
|
bool motion = motion_time != 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
if (!motion) {
|
|
|
|
|
/* prepare for sync */
|
|
|
|
|
light_map.pre_sync();
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_map.pre_sync();
|
2012-04-30 12:49:26 +00:00
|
|
|
object_map.pre_sync();
|
2021-08-19 14:34:01 +02:00
|
|
|
procedural_map.pre_sync();
|
2012-10-18 15:00:32 +00:00
|
|
|
particle_system_map.pre_sync();
|
2014-03-29 13:03:46 +01:00
|
|
|
motion_times.clear();
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2013-10-17 16:05:57 +00:00
|
|
|
else {
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_motion_synced.clear();
|
2013-10-17 16:05:57 +00:00
|
|
|
}
|
2021-11-04 18:32:01 +01:00
|
|
|
instance_geometries_by_object.clear();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-13 00:45:16 +01:00
|
|
|
/* initialize culling */
|
|
|
|
|
BlenderObjectCulling culling(scene, b_scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* object loop */
|
2012-09-04 13:29:07 +00:00
|
|
|
bool cancel = false;
|
Cycles: Added support for light portals
This patch adds support for light portals: objects that help sampling the
environment light, therefore improving convergence. Using them tor other
lights in a unidirectional pathtracer is virtually useless.
The sampling is done with the area-preserving code already used for area lamps.
MIS is used both for combination of different portals and for combining portal-
and envmap-sampling.
The direction of portals is considered, they aren't used if the sampling point
is behind them.
Reviewers: sergey, dingto, #cycles
Reviewed By: dingto, #cycles
Subscribers: Lapineige, nutel, jtheninja, dsisco11, januz, vitorbalbio, candreacchio, TARDISMaker, lichtwerk, ace_dragon, marcog, mib2berlin, Tunge, lopataasdf, lordodin, sergey, dingto
Differential Revision: https://developer.blender.org/D1133
2015-04-28 00:51:55 +05:00
|
|
|
bool use_portal = false;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-25 12:26:09 +02:00
|
|
|
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
2018-05-30 15:21:21 +02:00
|
|
|
BL::Depsgraph::object_instances_iterator b_instance_iter;
|
2020-10-21 16:38:36 +02:00
|
|
|
|
2018-05-30 15:21:21 +02:00
|
|
|
for (b_depsgraph.object_instances.begin(b_instance_iter);
|
|
|
|
|
b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
|
|
|
|
|
++b_instance_iter)
|
|
|
|
|
{
|
|
|
|
|
BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
|
|
|
|
|
BL::Object b_ob = b_instance.object();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-02 13:09:18 +01:00
|
|
|
/* Viewport visibility. */
|
|
|
|
|
const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
|
|
|
|
|
if (show_in_viewport == false) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Load per-object culling data. */
|
2017-04-25 16:18:24 +02:00
|
|
|
culling.init_object(scene, b_ob);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-23 17:13:21 +02:00
|
|
|
/* Ensure the object geom supporting the hair is processed before adding
|
|
|
|
|
* the hair processing task to the task pool, calling .to_mesh() on the
|
|
|
|
|
* same object in parallel does not work. */
|
|
|
|
|
const bool sync_hair = b_instance.show_particles() && object_has_particle_hair(b_ob);
|
|
|
|
|
|
2020-02-02 13:09:18 +01:00
|
|
|
/* Object itself. */
|
|
|
|
|
if (b_instance.show_self()) {
|
2021-08-19 14:34:01 +02:00
|
|
|
#ifdef WITH_ALEMBIC
|
|
|
|
|
bool use_procedural = false;
|
2021-08-20 02:30:50 +02:00
|
|
|
bool has_subdivision_modifier = false;
|
2021-08-19 14:34:01 +02:00
|
|
|
BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
|
|
|
|
|
|
2022-04-01 15:27:11 +02:00
|
|
|
/* Experimental as Blender does not have good support for procedurals at the moment. */
|
|
|
|
|
if (experimental) {
|
2021-09-09 17:22:20 +02:00
|
|
|
b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
|
2021-08-19 14:34:01 +02:00
|
|
|
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (use_procedural) {
|
|
|
|
|
/* Skip in the motion case, as generating motion blur data will be handled in the
|
|
|
|
|
* procedural. */
|
|
|
|
|
if (!motion) {
|
2021-08-20 02:30:50 +02:00
|
|
|
sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier);
|
2021-08-19 14:34:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
sync_object(b_depsgraph,
|
|
|
|
|
b_view_layer,
|
|
|
|
|
b_instance,
|
|
|
|
|
motion_time,
|
|
|
|
|
false,
|
|
|
|
|
show_lights,
|
|
|
|
|
culling,
|
|
|
|
|
&use_portal,
|
2024-12-26 17:53:55 +01:00
|
|
|
sync_hair ? nullptr : &geom_task_pool);
|
2021-08-19 14:34:01 +02:00
|
|
|
}
|
2020-02-02 13:09:18 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-02 13:09:18 +01:00
|
|
|
/* Particle hair as separate object. */
|
2020-10-23 17:13:21 +02:00
|
|
|
if (sync_hair) {
|
2018-02-26 16:46:48 +01:00
|
|
|
sync_object(b_depsgraph,
|
2018-07-25 12:26:09 +02:00
|
|
|
b_view_layer,
|
2018-05-30 15:21:21 +02:00
|
|
|
b_instance,
|
2017-04-25 16:18:24 +02:00
|
|
|
motion_time,
|
2020-02-02 13:09:18 +01:00
|
|
|
true,
|
2019-08-27 15:47:30 +02:00
|
|
|
show_lights,
|
2017-04-25 16:18:24 +02:00
|
|
|
culling,
|
2020-10-21 16:38:36 +02:00
|
|
|
&use_portal,
|
|
|
|
|
&geom_task_pool);
|
2017-04-25 16:18:24 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-25 16:18:24 +02:00
|
|
|
cancel = progress.get_cancel();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 16:38:36 +02:00
|
|
|
geom_task_pool.wait_work();
|
|
|
|
|
|
2012-09-28 12:37:20 +00:00
|
|
|
progress.set_sync_status("");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
if (!cancel && !motion) {
|
2019-08-27 15:47:30 +02:00
|
|
|
sync_background_light(b_v3d, use_portal);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-05-02 02:23:34 +02:00
|
|
|
/* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
|
2021-05-04 00:42:34 +10:00
|
|
|
* right order to ensure that dependent data is freed after their users. Objects should be
|
2021-05-02 02:23:34 +02:00
|
|
|
* freed before particle systems and geometries. */
|
2020-10-29 14:40:29 +01:00
|
|
|
light_map.post_sync();
|
|
|
|
|
object_map.post_sync();
|
2021-05-02 02:23:34 +02:00
|
|
|
geometry_map.post_sync();
|
2020-10-29 14:40:29 +01:00
|
|
|
particle_system_map.post_sync();
|
2021-08-19 14:34:01 +02:00
|
|
|
procedural_map.post_sync();
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (motion) {
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_motion_synced.clear();
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
void BlenderSync::sync_motion(BL::RenderSettings &b_render,
|
2018-02-26 16:46:48 +01:00
|
|
|
BL::Depsgraph &b_depsgraph,
|
2019-08-27 15:47:30 +02:00
|
|
|
BL::SpaceView3D &b_v3d,
|
2016-01-30 14:18:29 +01:00
|
|
|
BL::Object &b_override,
|
2015-07-21 15:36:35 +02:00
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
void **python_thread_state)
|
2012-04-30 12:49:26 +00:00
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (scene->need_motion() == Scene::MOTION_NONE) {
|
2012-04-30 12:49:26 +00:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
/* get camera object here to deal with camera switch */
|
|
|
|
|
BL::Object b_cam = b_scene.camera();
|
2023-09-17 09:01:48 +10:00
|
|
|
if (b_override) {
|
2012-04-30 12:49:26 +00:00
|
|
|
b_cam = b_override;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
int frame_center = b_scene.frame_current();
|
2016-09-14 14:58:55 +02:00
|
|
|
float subframe_center = b_scene.frame_subframe();
|
2015-06-29 17:40:13 +02:00
|
|
|
float frame_center_delta = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-29 17:40:13 +02:00
|
|
|
if (scene->need_motion() != Scene::MOTION_PASS &&
|
2022-04-19 16:28:14 +02:00
|
|
|
scene->camera->get_motion_position() != MOTION_POSITION_CENTER)
|
|
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
float shuttertime = scene->camera->get_shuttertime();
|
2022-04-19 16:28:14 +02:00
|
|
|
if (scene->camera->get_motion_position() == MOTION_POSITION_END) {
|
2015-06-29 17:40:13 +02:00
|
|
|
frame_center_delta = -shuttertime * 0.5f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-04-19 16:28:14 +02:00
|
|
|
assert(scene->camera->get_motion_position() == MOTION_POSITION_START);
|
2015-06-29 17:40:13 +02:00
|
|
|
frame_center_delta = shuttertime * 0.5f;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-14 14:58:55 +02:00
|
|
|
float time = frame_center + subframe_center + frame_center_delta;
|
2015-06-29 17:40:13 +02:00
|
|
|
int frame = (int)floorf(time);
|
|
|
|
|
float subframe = time - frame;
|
|
|
|
|
python_thread_state_restore(python_thread_state);
|
|
|
|
|
b_engine.frame_set(frame, subframe);
|
|
|
|
|
python_thread_state_save(python_thread_state);
|
2020-08-17 14:20:37 +02:00
|
|
|
if (b_cam) {
|
|
|
|
|
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
|
|
|
|
|
}
|
2021-05-11 14:22:40 +02:00
|
|
|
sync_objects(b_depsgraph, b_v3d);
|
2015-06-29 17:40:13 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-19 02:51:27 +02:00
|
|
|
/* Insert motion times from camera. Motion times from other objects
|
|
|
|
|
* have already been added in a sync_objects call. */
|
2020-08-17 14:20:37 +02:00
|
|
|
if (b_cam) {
|
|
|
|
|
uint camera_motion_steps = object_motion_steps(b_cam, b_cam);
|
|
|
|
|
for (size_t step = 0; step < camera_motion_steps; step++) {
|
|
|
|
|
motion_times.insert(scene->camera->motion_time(step));
|
|
|
|
|
}
|
2020-05-19 02:51:27 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-09 17:22:20 +02:00
|
|
|
/* Check which geometry already has motion blur so it can be skipped. */
|
|
|
|
|
geometry_motion_attribute_synced.clear();
|
|
|
|
|
for (Geometry *geom : scene->geometry) {
|
|
|
|
|
if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
|
|
|
|
|
geometry_motion_attribute_synced.insert(geom);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* note iteration over motion_times set happens in sorted order */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (float relative_time : motion_times) {
|
2018-03-10 00:37:07 +01:00
|
|
|
/* center time is already handled. */
|
|
|
|
|
if (relative_time == 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-06-16 19:39:13 +02:00
|
|
|
VLOG_WORK << "Synchronizing motion for the relative time " << relative_time << ".";
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* fixed shutter time to get previous and next frame for motion pass */
|
2016-07-16 18:56:59 +02:00
|
|
|
float shuttertime = scene->motion_shutter_time();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* compute frame and subframe time */
|
2016-09-14 14:58:55 +02:00
|
|
|
float time = frame_center + subframe_center + frame_center_delta +
|
|
|
|
|
relative_time * shuttertime * 0.5f;
|
2014-03-29 13:03:46 +01:00
|
|
|
int frame = (int)floorf(time);
|
|
|
|
|
float subframe = time - frame;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* change frame */
|
2014-02-12 23:13:45 +01:00
|
|
|
python_thread_state_restore(python_thread_state);
|
2014-05-21 15:47:11 +02:00
|
|
|
b_engine.frame_set(frame, subframe);
|
2014-02-12 23:13:45 +01:00
|
|
|
python_thread_state_save(python_thread_state);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-19 02:51:27 +02:00
|
|
|
/* Syncs camera motion if relative_time is one of the camera's motion times. */
|
|
|
|
|
sync_camera_motion(b_render, b_cam, width, height, relative_time);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
/* sync object */
|
2019-08-27 15:47:30 +02:00
|
|
|
sync_objects(b_depsgraph, b_v3d, relative_time);
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-09 17:22:20 +02:00
|
|
|
geometry_motion_attribute_synced.clear();
|
|
|
|
|
|
2014-02-12 21:49:34 +01:00
|
|
|
/* we need to set the python thread state again because this
|
|
|
|
|
* function assumes it is being executed from python and will
|
|
|
|
|
* try to save the thread state */
|
2014-02-12 23:13:45 +01:00
|
|
|
python_thread_state_restore(python_thread_state);
|
2016-09-14 14:58:55 +02:00
|
|
|
b_engine.frame_set(frame_center, subframe_center);
|
2014-02-12 23:13:45 +01:00
|
|
|
python_thread_state_save(python_thread_state);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|