Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-04-19 23:24:55 +02:00
commit 44fd07c1c8
15 changed files with 286 additions and 154 deletions

View File

@ -93,6 +93,7 @@ set(SRC_BVH_HEADERS
bvh/bvh_local.h
bvh/bvh_traversal.h
bvh/bvh_types.h
bvh/bvh_util.h
bvh/bvh_volume.h
bvh/bvh_volume_all.h
bvh/bvh_embree.h

View File

@ -29,9 +29,10 @@
# include "kernel/bvh/bvh_embree.h"
#endif
CCL_NAMESPACE_BEGIN
#include "kernel/bvh/bvh_types.h"
#include "kernel/bvh/bvh_util.h"
CCL_NAMESPACE_BEGIN
#ifndef __KERNEL_OPTIX__
@ -533,97 +534,4 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
}
#endif /* __VOLUME_RECORD_ALL__ */
/* Ray offset to avoid self intersection.
*
* This function should be used to compute a modified ray start position for
* rays leaving from a surface. */
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
{
#ifdef __INTERSECTION_REFINE__
const float epsilon_f = 1e-5f;
/* ideally this should match epsilon_f, but instancing and motion blur
* precision makes it problematic */
const float epsilon_test = 1.0f;
const int epsilon_i = 32;
float3 res;
/* x component */
if (fabsf(P.x) < epsilon_test) {
res.x = P.x + Ng.x * epsilon_f;
}
else {
uint ix = __float_as_uint(P.x);
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
res.x = __uint_as_float(ix);
}
/* y component */
if (fabsf(P.y) < epsilon_test) {
res.y = P.y + Ng.y * epsilon_f;
}
else {
uint iy = __float_as_uint(P.y);
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
res.y = __uint_as_float(iy);
}
/* z component */
if (fabsf(P.z) < epsilon_test) {
res.z = P.z + Ng.z * epsilon_f;
}
else {
uint iz = __float_as_uint(P.z);
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
res.z = __uint_as_float(iz);
}
return res;
#else
const float epsilon_f = 1e-4f;
return P + epsilon_f * Ng;
#endif
}
#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
/* ToDo: Move to another file? */
ccl_device int intersections_compare(const void *a, const void *b)
{
const Intersection *isect_a = (const Intersection *)a;
const Intersection *isect_b = (const Intersection *)b;
if (isect_a->t < isect_b->t)
return -1;
else if (isect_a->t > isect_b->t)
return 1;
else
return 0;
}
#endif
#if defined(__SHADOW_RECORD_ALL__)
ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
{
# ifdef __KERNEL_GPU__
/* Use bubble sort which has more friendly memory pattern on GPU. */
bool swapped;
do {
swapped = false;
for (int j = 0; j < num_hits - 1; ++j) {
if (hits[j].t > hits[j + 1].t) {
struct Intersection tmp = hits[j];
hits[j] = hits[j + 1];
hits[j + 1] = tmp;
swapped = true;
}
}
--num_hits;
} while (swapped);
# else
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
# endif
}
#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
CCL_NAMESPACE_END

View File

@ -180,25 +180,10 @@ ccl_device_inline
/* todo: optimize so primitive visibility flag indicates if
* the primitive has a transparent shadow shader? */
int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
int shader = 0;
#ifdef __HAIR__
if (kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
#endif
{
shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __HAIR__
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
#endif
int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
const int flags = intersection_get_shader_flags(kg, isect_array);
/* if no transparent shadows, all light is blocked */
if (!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
if (!(flags & SD_HAS_TRANSPARENT_SHADOW)) {
return true;
}
/* if maximum number of hits reached, block all light */

View File

@ -0,0 +1,162 @@
/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
CCL_NAMESPACE_BEGIN
/* Ray offset to avoid self intersection.
*
* This function should be used to compute a modified ray start position for
* rays leaving from a surface. */
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
{
#ifdef __INTERSECTION_REFINE__
const float epsilon_f = 1e-5f;
/* ideally this should match epsilon_f, but instancing and motion blur
* precision makes it problematic */
const float epsilon_test = 1.0f;
const int epsilon_i = 32;
float3 res;
/* x component */
if (fabsf(P.x) < epsilon_test) {
res.x = P.x + Ng.x * epsilon_f;
}
else {
uint ix = __float_as_uint(P.x);
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
res.x = __uint_as_float(ix);
}
/* y component */
if (fabsf(P.y) < epsilon_test) {
res.y = P.y + Ng.y * epsilon_f;
}
else {
uint iy = __float_as_uint(P.y);
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
res.y = __uint_as_float(iy);
}
/* z component */
if (fabsf(P.z) < epsilon_test) {
res.z = P.z + Ng.z * epsilon_f;
}
else {
uint iz = __float_as_uint(P.z);
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
res.z = __uint_as_float(iz);
}
return res;
#else
const float epsilon_f = 1e-4f;
return P + epsilon_f * Ng;
#endif
}
#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
/* ToDo: Move to another file? */
ccl_device int intersections_compare(const void *a, const void *b)
{
const Intersection *isect_a = (const Intersection *)a;
const Intersection *isect_b = (const Intersection *)b;
if (isect_a->t < isect_b->t)
return -1;
else if (isect_a->t > isect_b->t)
return 1;
else
return 0;
}
#endif
#if defined(__SHADOW_RECORD_ALL__)
ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
{
kernel_assert(num_hits > 0);
# ifdef __KERNEL_GPU__
/* Use bubble sort which has more friendly memory pattern on GPU. */
bool swapped;
do {
swapped = false;
for (int j = 0; j < num_hits - 1; ++j) {
if (hits[j].t > hits[j + 1].t) {
struct Intersection tmp = hits[j];
hits[j] = hits[j + 1];
hits[j + 1] = tmp;
swapped = true;
}
}
--num_hits;
} while (swapped);
# else
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
# endif
}
#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
/* Utility to quickly get a shader flags from an intersection. */
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals *ccl_restrict kg,
const Intersection *isect)
{
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
int shader = 0;
#ifdef __HAIR__
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
#endif
{
shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __HAIR__
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
#endif
return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
}
ccl_device_forceinline int intersection_get_shader(KernelGlobals *ccl_restrict kg,
const Intersection *isect)
{
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
int shader = 0;
#ifdef __HAIR__
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
#endif
{
shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __HAIR__
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
#endif
return shader & SHADER_MASK;
}
CCL_NAMESPACE_END

View File

@ -65,7 +65,6 @@ ccl_device_forceinline bool kernel_path_scene_intersect(KernelGlobals *kg,
uint visibility = path_state_ray_visibility(kg, state);
if (path_state_ao_bounce(kg, state)) {
visibility = PATH_RAY_SHADOW;
ray->t = kernel_data.background.ao_distance;
}
@ -416,7 +415,13 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
break;
}
else if (path_state_ao_bounce(kg, state)) {
break;
if (intersection_get_shader_flags(kg, &isect) &
(SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
}
else {
break;
}
}
/* Setup shader data. */
@ -554,7 +559,13 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
break;
}
else if (path_state_ao_bounce(kg, state)) {
break;
if (intersection_get_shader_flags(kg, &isect) &
(SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
}
else {
break;
}
}
/* Setup shader data. */

View File

@ -895,6 +895,8 @@ enum ShaderDataFlag {
SD_HAS_CONSTANT_EMISSION = (1 << 27),
/* Needs to access attributes for volume rendering */
SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
/* Shader has emission */
SD_HAS_EMISSION = (1 << 29),
SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME |
SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR |

View File

@ -528,6 +528,8 @@ void ShaderManager::device_update_common(Device *device,
if (shader->get_use_mis())
flag |= SD_USE_MIS;
if (shader->has_surface_emission)
flag |= SD_HAS_EMISSION;
if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
flag |= SD_HAS_TRANSPARENT_SHADOW;
if (shader->has_volume) {

View File

@ -152,6 +152,7 @@ void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bma
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, const bool clear_recalc);
void BKE_scene_view_layer_graph_evaluated_ensure(struct Main *bmain,
struct Scene *scene,

View File

@ -2636,6 +2636,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
bool used_multiple_passes = false;
bool run_callbacks = DEG_id_type_any_updated(depsgraph);
if (run_callbacks) {
@ -2672,8 +2673,6 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
* If there are no relations changed by the callback this call will do nothing. */
DEG_graph_relations_update(depsgraph);
}
/* Inform editors about possible changes. */
DEG_editors_update(bmain, depsgraph, scene, view_layer, false);
/* If user callback did not tag anything for update we can skip second iteration.
* Otherwise we update scene once again, but without running callbacks to bring
@ -2682,8 +2681,22 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
break;
}
/* Clear recalc flags for second pass, but back them up for editors update. */
const bool backup = true;
DEG_ids_clear_recalc(depsgraph, backup);
used_multiple_passes = true;
run_callbacks = false;
}
/* Inform editors about changes, using recalc flags from both passes. */
if (used_multiple_passes) {
DEG_ids_restore_recalc(depsgraph);
}
const bool is_time_update = false;
DEG_editors_update(depsgraph, is_time_update);
const bool backup = false;
DEG_ids_clear_recalc(depsgraph, backup);
}
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
@ -2697,11 +2710,11 @@ void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
}
/* applies changes right away, does all sets too */
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool clear_recalc)
{
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
Main *bmain = DEG_get_bmain(depsgraph);
bool used_multiple_passes = false;
/* Keep this first. */
BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
@ -2738,16 +2751,38 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
DEG_graph_relations_update(depsgraph);
}
/* Inform editors about possible changes. */
DEG_editors_update(bmain, depsgraph, scene, view_layer, true);
/* If user callback did not tag anything for update we can skip second iteration.
* Otherwise we update scene once again, but without running callbacks to bring
* scene to a fully evaluated state with user modifications taken into account. */
if (DEG_is_fully_evaluated(depsgraph)) {
break;
}
/* Clear recalc flags for second pass, but back them up for editors update. */
const bool backup = true;
DEG_ids_clear_recalc(depsgraph, backup);
used_multiple_passes = true;
}
/* Inform editors about changes, using recalc flags from both passes. */
if (used_multiple_passes) {
DEG_ids_restore_recalc(depsgraph);
}
const bool is_time_update = true;
DEG_editors_update(depsgraph, is_time_update);
/* Clear recalc flags, can be skipped for e.g. renderers that will read these
* and clear the flags later. */
if (clear_recalc) {
const bool backup = false;
DEG_ids_clear_recalc(depsgraph, backup);
}
}
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
{
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
}
/**
@ -3507,8 +3542,8 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain)
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
if (scene->depsgraph_hash == NULL) {
/* In some cases, e.g. when undo has to perform multiple steps at once, no depsgraph will be
* built so this pointer may be NULL. */
/* In some cases, e.g. when undo has to perform multiple steps at once, no depsgraph will
* be built so this pointer may be NULL. */
continue;
}
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;

View File

@ -143,16 +143,15 @@ void DEG_id_type_tag(struct Main *bmain, short id_type);
* for viewport depsgraphs, but not render or export depsgraph for example. */
void DEG_enable_editors_update(struct Depsgraph *depsgraph);
/* Check if something was changed in the database and inform editors about this,
* then clear recalc flags. */
void DEG_editors_update(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct ViewLayer *view_layer,
bool time);
/* Check if something was changed in the database and inform editors about this. */
void DEG_editors_update(struct Depsgraph *depsgraph, bool time);
/* Clear recalc flags after editors or renderers have handled updates. */
void DEG_ids_clear_recalc(Depsgraph *depsgraph);
void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup);
/* Restore recalc flags, backed up by a previous call to DEG_ids_clear_recalc.
* This also clears the backup. */
void DEG_ids_restore_recalc(Depsgraph *depsgraph);
/* ************************************************ */
/* Evaluation Engine API */

View File

@ -824,23 +824,24 @@ void DEG_enable_editors_update(Depsgraph *depsgraph)
/* Check if something was changed in the database and inform
* editors about this. */
void DEG_editors_update(
Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, bool time)
void DEG_editors_update(Depsgraph *depsgraph, bool time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
if (graph->use_editors_update) {
bool updated = time || DEG_id_type_any_updated(depsgraph);
DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
update_ctx.depsgraph = depsgraph;
update_ctx.scene = scene;
update_ctx.view_layer = view_layer;
deg::deg_editors_scene_update(&update_ctx, updated);
if (!graph->use_editors_update) {
return;
}
DEG_ids_clear_recalc(depsgraph);
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
Main *bmain = DEG_get_bmain(depsgraph);
bool updated = time || DEG_id_type_any_updated(depsgraph);
DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
update_ctx.depsgraph = depsgraph;
update_ctx.scene = scene;
update_ctx.view_layer = view_layer;
deg::deg_editors_scene_update(&update_ctx, updated);
}
static void deg_graph_clear_id_recalc_flags(ID *id)
@ -854,7 +855,7 @@ static void deg_graph_clear_id_recalc_flags(ID *id)
/* XXX And what about scene's master collection here? */
}
void DEG_ids_clear_recalc(Depsgraph *depsgraph)
void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
/* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
@ -864,6 +865,9 @@ void DEG_ids_clear_recalc(Depsgraph *depsgraph)
}
/* Go over all ID nodes nodes, clearing tags. */
for (deg::IDNode *id_node : deg_graph->id_nodes) {
if (backup) {
id_node->id_cow_recalc_backup |= id_node->id_cow->recalc;
}
/* TODO: we clear original ID recalc flags here, but this may not work
* correctly when there are multiple depsgraph with others still using
* the recalc flag. */
@ -875,3 +879,13 @@ void DEG_ids_clear_recalc(Depsgraph *depsgraph)
}
memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated));
}
void DEG_ids_restore_recalc(Depsgraph *depsgraph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
for (deg::IDNode *id_node : deg_graph->id_nodes) {
id_node->id_cow->recalc |= id_node->id_cow_recalc_backup;
id_node->id_cow_recalc_backup = 0;
}
}

View File

@ -90,6 +90,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata))
is_collection_fully_expanded = false;
has_base = false;
is_user_modified = false;
id_cow_recalc_backup = 0;
visible_components_mask = 0;
previously_visible_components_mask = 0;

View File

@ -120,6 +120,9 @@ struct IDNode : public Node {
/* Accumulated flag from operation. Is initialized and used during updates flush. */
bool is_user_modified;
/* Accumulate recalc flags from multiple update passes. */
int id_cow_recalc_backup;
IDComponentsMask visible_components_mask;
IDComponentsMask previously_visible_components_mask;

View File

@ -886,7 +886,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
if (treedata->tree == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
BLI_assert(sod->treedata_editmesh.em ==
BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
em = sod->treedata_editmesh.em;
if (sctx->callbacks.edit_mesh.test_face_fn) {
@ -2276,7 +2277,7 @@ static short snapMesh(SnapObjectContext *sctx,
if (me_eval->totvert == 0) {
return 0;
}
else if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
return 0;
}
@ -3115,8 +3116,15 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
elem_test = snap_mesh_polygon(
sctx, &snapdata, ob_eval, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
elem_test = snap_mesh_polygon(sctx,
&snapdata,
ob_eval,
obmat,
params->use_backface_culling,
&dist_px_tmp,
loc,
no,
&index);
if (elem_test) {
elem = elem_test;
}

View File

@ -690,7 +690,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
}
else {
/* Go through update with full Python callbacks for regular render. */
BKE_scene_graph_update_for_newframe(engine->depsgraph);
BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
}
engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph);
@ -702,7 +702,7 @@ static void engine_depsgraph_exit(RenderEngine *engine)
if (engine_keep_depsgraph(engine)) {
/* Clear recalc flags since the engine should have handled the updates for the currently
* rendered framed by now. */
DEG_ids_clear_recalc(engine->depsgraph);
DEG_ids_clear_recalc(engine->depsgraph, false);
}
else {
/* Free immediately to save memory. */
@ -718,14 +718,14 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
}
/* Clear recalc flags before update so engine can detect what changed. */
DEG_ids_clear_recalc(engine->depsgraph);
DEG_ids_clear_recalc(engine->depsgraph, false);
Render *re = engine->re;
double cfra = (double)frame + (double)subframe;
CLAMP(cfra, MINAFRAME, MAXFRAME);
BKE_scene_frame_set(re->scene, cfra);
BKE_scene_graph_update_for_newframe(engine->depsgraph);
BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
BKE_scene_camera_switch_update(re->scene);
}