diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 7036e58f6fb..f763fe0eb0b 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1880,6 +1880,12 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel): layout.prop(rd, "use_bake_multires") layout.prop(cscene, "bake_type") + if not rd.use_bake_multires and cscene.bake_type not in { + "AO", "POSITION", "NORMAL", "UV", "ROUGHNESS", "ENVIRONMENT"}: + row = layout.row() + row.prop(cbk, "view_from") + row.active = scene.camera is not None + class CYCLES_RENDER_PT_bake_influence(CyclesButtonsPanel, Panel): bl_label = "Influence" diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp index 6926c833096..d7def9fdb7c 100644 --- a/intern/cycles/blender/camera.cpp +++ b/intern/cycles/blender/camera.cpp @@ -2,6 +2,7 @@ * Copyright 2011-2022 Blender Foundation */ #include "scene/camera.h" +#include "scene/bake.h" #include "scene/scene.h" #include "blender/sync.h" @@ -592,6 +593,11 @@ void BlenderSync::sync_camera(BL::RenderSettings &b_render, blender_camera_from_object(&bcam, b_engine, b_ob); b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); bcam.matrix = get_transform(b_ob_matrix); + scene->bake_manager->set_use_camera(b_render.bake().view_from() == + BL::BakeSettings::view_from_ACTIVE_CAMERA); + } + else { + scene->bake_manager->set_use_camera(false); } /* sync */ diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h index eca2c0b9ffb..15968670ac2 100644 --- a/intern/cycles/kernel/integrator/init_from_bake.h +++ b/intern/cycles/kernel/integrator/init_from_bake.h @@ -210,8 +210,51 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, /* Setup ray. */ Ray ray ccl_optional_struct_init; - ray.P = P + N; - ray.D = -N; + + if (kernel_data.bake.use_camera) { + float3 D = camera_direction_from_point(kg, P); + + const float DN = dot(D, N); + + /* Nudge camera direction, so that the faces facing away from the camera still have + * somewhat usable shading. (Otherwise, glossy faces would be simply black.) + * + * The surface normal offset affects smooth surfaces. Lower values will make + * smooth surfaces more faceted, but higher values may show up from the camera + * at grazing angles. + * + * This value can actually be pretty high before it's noticeably wrong. */ + const float surface_normal_offset = 0.2f; + + /* Keep the ray direction at least `surface_normal_offset` "above" the smooth normal. */ + if (DN <= surface_normal_offset) { + D -= N * (DN - surface_normal_offset); + D = normalize(D); + } + + /* On the backside, just lerp towards the surface normal for the ray direction, + * as DN goes from 0.0 to -1.0. */ + if (DN <= 0.0f) { + D = normalize(mix(D, N, -DN)); + } + + /* We don't want to bake the back face, so make sure the ray direction never + * goes behind the geometry (flat) normal. This is a failsafe, and should rarely happen. */ + const float true_normal_epsilon = 0.00001f; + + if (dot(D, Ng) <= true_normal_epsilon) { + D -= Ng * (dot(D, Ng) - true_normal_epsilon); + D = normalize(D); + } + + ray.P = P + D; + ray.D = -D; + } + else { + ray.P = P + N; + ray.D = -N; + } + ray.tmin = 0.0f; ray.tmax = FLT_MAX; ray.time = 0.5f; diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index f81e7843629..1469d915d15 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1160,7 +1160,7 @@ typedef struct KernelBake { int use; int object_index; int tri_offset; - int pad1; + int use_camera; } KernelBake; static_assert_align(KernelBake, 16); diff --git a/intern/cycles/scene/bake.cpp b/intern/cycles/scene/bake.cpp index 1947b9d71a4..768e723b587 100644 --- a/intern/cycles/scene/bake.cpp +++ b/intern/cycles/scene/bake.cpp @@ -16,6 +16,7 @@ CCL_NAMESPACE_BEGIN BakeManager::BakeManager() { need_update_ = true; + use_camera_ = false; } BakeManager::~BakeManager() @@ -38,6 +39,14 @@ void BakeManager::set(Scene *scene, const std::string &object_name_) need_update_ = true; } +void BakeManager::set_use_camera(const bool use_camera) +{ + if (use_camera_ != use_camera) { + use_camera_ = use_camera; + need_update_ = true; + } +} + void BakeManager::device_update(Device * /*device*/, DeviceScene *dscene, Scene *scene, @@ -49,6 +58,8 @@ void BakeManager::device_update(Device * /*device*/, KernelBake *kbake = &dscene->data.bake; memset(kbake, 0, sizeof(*kbake)); + kbake->use_camera = use_camera_; + if (!object_name.empty()) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { diff --git a/intern/cycles/scene/bake.h b/intern/cycles/scene/bake.h index 0d90ece5628..e3f3911ab05 100644 --- a/intern/cycles/scene/bake.h +++ b/intern/cycles/scene/bake.h @@ -20,6 +20,8 @@ class BakeManager { void set(Scene *scene, const std::string &object_name); bool get_baking() const; + void set_use_camera(bool use_camera); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); void device_free(Device *device, DeviceScene *dscene); @@ -30,6 +32,7 @@ class BakeManager { private: bool need_update_; std::string object_name; + bool use_camera_; }; CCL_NAMESPACE_END diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 80b1049ca23..2db81693f51 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -559,7 +559,8 @@ typedef struct BakeData { char target; char save_mode; char margin_type; - char _pad[5]; + char view_from; + char _pad[4]; struct Object *cage_object; } BakeData; @@ -592,6 +593,12 @@ typedef enum eBakeSaveMode { R_BAKE_SAVE_EXTERNAL = 1, } eBakeSaveMode; +/** #BakeData.view_from (char) */ +typedef enum eBakeViewFrom { + R_BAKE_VIEW_FROM_ABOVE_SURFACE = 0, + R_BAKE_VIEW_FROM_ACTIVE_CAMERA = 1, +} eBakeViewFrom; + /** #BakeData.pass_filter */ typedef enum eBakePassFilter { R_BAKE_PASS_FILTER_NONE = 0, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index da30b7f2136..fdf8be9cb33 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -476,6 +476,20 @@ const EnumPropertyItem rna_enum_bake_save_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_bake_view_from_items[] = { + {R_BAKE_VIEW_FROM_ABOVE_SURFACE, + "ABOVE_SURFACE", + 0, + "Above Surface", + "Cast rays from above the surface"}, + {R_BAKE_VIEW_FROM_ACTIVE_CAMERA, + "ACTIVE_CAMERA", + 0, + "Active Camera", + "Use the active camera's position to cast rays"}, + {0, NULL, 0, NULL, NULL}, +}; + #define R_IMF_VIEWS_ENUM_IND \ {R_IMF_VIEWS_INDIVIDUAL, \ "INDIVIDUAL", \ @@ -5413,6 +5427,11 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Save Mode", "Where to save baked image textures"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "view_from", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_bake_view_from_items); + RNA_def_property_ui_text(prop, "View From", "Source of reflection ray directions"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + /* flags */ prop = RNA_def_property(srna, "use_selected_to_active", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_TO_ACTIVE);