UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
150 changed files with 1749 additions and 563 deletions
Showing only changes of commit c12ac8bef6 - Show all commits

View File

@ -689,7 +689,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "clang", # clang-format is part of the main clang package.
},
),
Package(name="Python", is_mandatory=True, version="3.10.9", version_short="3.10", version_min="3.10", version_mex="3.12",
Package(name="Python", is_mandatory=True, version="3.10.11", version_short="3.10", version_min="3.10", version_mex="3.12",
sub_packages=PYTHON_SUBPACKAGES,
distro_package_names={DISTRO_ID_DEBIAN: "python3-dev",
DISTRO_ID_FEDORA: "python3-devel",
@ -721,7 +721,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "opencolorio",
},
),
Package(name="IMath Library", is_mandatory=False, version="3.1.5", version_short="3.1", version_min="3.0", version_mex="4.0",
Package(name="IMath Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: "libimath-dev",
DISTRO_ID_FEDORA: "imath-devel",
@ -729,7 +729,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "imath",
},
),
Package(name="OpenEXR Library", is_mandatory=False, version="3.1.5", version_short="3.1", version_min="3.0", version_mex="4.0",
Package(name="OpenEXR Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: "libopenexr-dev",
DISTRO_ID_FEDORA: "openexr-devel",
@ -737,7 +737,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "openexr",
},
),
Package(name="OpenImageIO Library", is_mandatory=True, version="2.4.9.0", version_short="2.4", version_min="2.2.0", version_mex="2.5.0",
Package(name="OpenImageIO Library", is_mandatory=True, version="2.4.11.0", version_short="2.4", version_min="2.2.0", version_mex="2.5.0",
sub_packages=(
Package(name="OpenImageIO Tools", is_mandatory=False,
distro_package_names={DISTRO_ID_DEBIAN: "openimageio-tools",
@ -836,7 +836,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "materialx-git",
},
),
Package(name="USD Library", is_mandatory=False, version="22.11", version_short="22.11", version_min="20.05", version_mex="23.00",
Package(name="USD Library", is_mandatory=False, version="23.05", version_short="23.05", version_min="20.05", version_mex="24.00",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: None,
DISTRO_ID_FEDORA: "usd-devel",
@ -851,7 +851,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "opencollada",
},
),
Package(name="Embree Library", is_mandatory=False, version="3.13.4", version_short="3.13", version_min="3.13", version_mex="5.0",
Package(name="Embree Library", is_mandatory=False, version="4.1.0", version_short="4.1", version_min="3.13", version_mex="5.0",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: "libembree-dev",
DISTRO_ID_FEDORA: "embree-devel",
@ -867,7 +867,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "openimagedenoise",
},
),
Package(name="Level Zero Library", is_mandatory=False, version="1.7.15", version_short="1.7", version_min="1.7", version_mex="2.0",
Package(name="Level Zero Library", is_mandatory=False, version="1.8.8", version_short="1.8", version_min="1.7", version_mex="2.0",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: None,
DISTRO_ID_FEDORA: "oneapi-level-zero-devel",
@ -875,7 +875,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "level-zero-headers", # ???
},
),
Package(name="OpenPGL Library", is_mandatory=False, version="0.4.1", version_short="0.4", version_min="0.4.1", version_mex="0.5",
Package(name="OpenPGL Library", is_mandatory=False, version="0.5.0", version_short="0.5", version_min="0.5.0", version_mex="0.6",
sub_packages=(),
distro_package_names={DISTRO_ID_DEBIAN: None,
DISTRO_ID_FEDORA: "openpgl-devel",
@ -891,7 +891,7 @@ PACKAGES_ALL = (
DISTRO_ID_ARCH: "openxr",
},
),
Package(name="FFMPEG Library", is_mandatory=False, version="5.1.2", version_short="5.1", version_min="4.0", version_mex="7.0",
Package(name="FFMPEG Library", is_mandatory=False, version="6.0", version_short="6.0", version_min="4.0", version_mex="7.0",
sub_packages=(
Package(name="AVDevice FFMPEG Library", is_mandatory=False,
distro_package_names={DISTRO_ID_DEBIAN: "libavdevice-dev",

View File

@ -209,6 +209,21 @@ enum_guiding_distribution = (
('VMM', "VMM", "Use von Mises-Fisher models as directional distribution", 2),
)
enum_guiding_directional_sampling_types = (
('MIS',
"Diffuse Product MIS",
"Guided diffuse BSDF component based on the incoming light distribution and the cosine product (closed form product)",
0),
('RIS',
"Re-sampled Importance Sampling",
"Perform RIS sampling to guided based on the product of the incoming light distribution and the BSDF",
1),
('ROUGHNESS',
"Roughness-based",
"Adjust the guiding probability based on the roughness of the material components",
2),
)
def enum_openimagedenoise_denoiser(self, context):
import _cycles
@ -568,6 +583,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default='PARALLAX_AWARE_VMM',
)
guiding_directional_sampling_type: EnumProperty(
name="Directional Sampling Type",
description="Type of the directional sampling used for guiding",
items=enum_guiding_directional_sampling_types,
default='RIS',
)
use_surface_guiding: BoolProperty(
name="Surface Guiding",
description="Use guiding when sampling directions on a surface",
@ -617,6 +639,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=True,
)
guiding_roughness_threshold: FloatProperty(
name="Guiding Roughness Threshold",
description="The minimal roughness value of a material to apply guiding",
min=0.0, max=1.0,
default=0.05,
)
max_bounces: IntProperty(
name="Max Bounces",
description="Total maximum number of bounces",

View File

@ -337,6 +337,8 @@ class CYCLES_RENDER_PT_sampling_path_guiding_debug(CyclesDebugButtonsPanel, Pane
layout.active = cscene.use_guiding
layout.prop(cscene, "guiding_distribution_type", text="Distribution Type")
layout.prop(cscene, "guiding_roughness_threshold")
layout.prop(cscene, "guiding_directional_sampling_type", text="Directional Sampling Type")
col = layout.column(align=True)
col.prop(cscene, "surface_guiding_probability")

View File

@ -30,6 +30,25 @@ int blender_device_threads(BL::Scene &b_scene)
return 0;
}
void adjust_device_info_from_preferences(DeviceInfo &info, PointerRNA cpreferences)
{
if (!get_boolean(cpreferences, "peer_memory")) {
info.has_peer_memory = false;
}
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
info.use_hardware_raytracing = false;
}
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
info.use_hardware_raytracing = false;
}
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
info.use_hardware_raytracing = false;
}
}
DeviceInfo blender_device_info(BL::Preferences &b_preferences,
BL::Scene &b_scene,
bool background,
@ -108,35 +127,17 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences,
}
}
if (!get_boolean(cpreferences, "peer_memory")) {
device.has_peer_memory = false;
}
adjust_device_info_from_preferences(device, cpreferences);
foreach (DeviceInfo &info, device.multi_devices) {
adjust_device_info_from_preferences(info, cpreferences);
bool accumulated_use_hardware_raytracing = false;
foreach (
DeviceInfo &info,
(device.multi_devices.size() != 0 ? device.multi_devices : vector<DeviceInfo>({device})))
{
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
info.use_hardware_raytracing = false;
}
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
info.use_hardware_raytracing = false;
}
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
info.use_hardware_raytracing = false;
}
/* There is an accumulative logic here, because Multi-devices are support only for
/* There is an accumulative logic here, because Multi-devices are supported only for
* the same backend + CPU in Blender right now, and both oneAPI and Metal have a
* global boolean backend setting (see above) for enabling/disabling HW RT,
* so all sub-devices in the multi-device should enable (or disable) HW RT
* simultaneously (and CPU device are expected to ignore `use_hardware_raytracing` setting). */
accumulated_use_hardware_raytracing |= info.use_hardware_raytracing;
* global boolean backend setting for enabling/disabling Hardware Ray Tracing,
* so all sub-devices in the multi-device should enable (or disable) Hardware Ray Tracing
* simultaneously (and CPU device is expected to ignore `use_hardware_raytracing` setting). */
device.use_hardware_raytracing |= info.use_hardware_raytracing;
}
device.use_hardware_raytracing = accumulated_use_hardware_raytracing;
if (preview) {
/* Disable specialization for preview renders. */

View File

@ -440,6 +440,13 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
GuidingDistributionType guiding_distribution_type = (GuidingDistributionType)get_enum(
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
integrator->set_guiding_distribution_type(guiding_distribution_type);
GuidingDirectionalSamplingType guiding_directional_sampling_type =
(GuidingDirectionalSamplingType)get_enum(cscene,
"guiding_directional_sampling_type",
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
integrator->set_guiding_directional_sampling_type(guiding_directional_sampling_type);
integrator->set_guiding_roughness_threshold(get_float(cscene, "guiding_roughness_threshold"));
}
DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);

View File

@ -33,12 +33,16 @@ const char *bvh_layout_name(BVHLayout layout)
return "METAL";
case BVH_LAYOUT_HIPRT:
return "HIPRT";
case BVH_LAYOUT_EMBREEGPU:
return "EMBREEGPU";
case BVH_LAYOUT_MULTI_OPTIX:
case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_HIPRT:
case BVH_LAYOUT_MULTI_EMBREEGPU:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
case BVH_LAYOUT_MULTI_METAL_EMBREE:
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
return "MULTI";
case BVH_LAYOUT_ALL:
return "ALL";
@ -88,6 +92,7 @@ BVH *BVH::create(const BVHParams &params,
case BVH_LAYOUT_BVH2:
return new BVH2(params, geometry, objects);
case BVH_LAYOUT_EMBREE:
case BVH_LAYOUT_EMBREEGPU:
#ifdef WITH_EMBREE
return new BVHEmbree(params, geometry, objects);
#else
@ -117,9 +122,11 @@ BVH *BVH::create(const BVHParams &params,
case BVH_LAYOUT_MULTI_OPTIX:
case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_HIPRT:
case BVH_LAYOUT_MULTI_EMBREEGPU:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
case BVH_LAYOUT_MULTI_METAL_EMBREE:
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
return new BVHMulti(params, geometry, objects);
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:

View File

@ -265,7 +265,8 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
#ifdef WITH_EMBREE
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE)
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
{
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
if (refit) {

View File

@ -122,6 +122,11 @@ class MultiDevice : public Device {
return BVH_LAYOUT_MULTI_HIPRT;
}
/* With multiple oneAPI devices, every device needs its own acceleration structure */
if (bvh_layout_mask == BVH_LAYOUT_EMBREEGPU) {
return BVH_LAYOUT_MULTI_EMBREEGPU;
}
/* When devices do not share a common BVH layout, fall back to creating one for each */
const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
@ -131,6 +136,10 @@ class MultiDevice : public Device {
if ((bvh_layout_mask_all & BVH_LAYOUT_METAL_EMBREE) == BVH_LAYOUT_METAL_EMBREE) {
return BVH_LAYOUT_MULTI_METAL_EMBREE;
}
const BVHLayoutMask BVH_LAYOUT_EMBREEGPU_EMBREE = (BVH_LAYOUT_EMBREEGPU | BVH_LAYOUT_EMBREE);
if ((bvh_layout_mask_all & BVH_LAYOUT_EMBREEGPU_EMBREE) == BVH_LAYOUT_EMBREEGPU_EMBREE) {
return BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
}
return bvh_layout_mask;
}
@ -164,9 +173,11 @@ class MultiDevice : public Device {
assert(bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE);
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE);
BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
bvh_multi->sub_bvhs.resize(devices.size());
@ -193,6 +204,8 @@ class MultiDevice : public Device {
params.bvh_layout = BVH_LAYOUT_METAL;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT)
params.bvh_layout = BVH_LAYOUT_HIPRT;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU)
params.bvh_layout = BVH_LAYOUT_EMBREEGPU;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
BVH_LAYOUT_EMBREE;
@ -202,7 +215,9 @@ class MultiDevice : public Device {
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE)
params.bvh_layout = sub.device->info.type == DEVICE_HIPRT ? BVH_LAYOUT_HIPRT :
BVH_LAYOUT_EMBREE;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
params.bvh_layout = sub.device->info.type == DEVICE_ONEAPI ? BVH_LAYOUT_EMBREEGPU :
BVH_LAYOUT_EMBREE;
/* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
* (since they are put into the top level directly, see bvh_embree.cpp) */
if (!params.top_level && params.bvh_layout == BVH_LAYOUT_EMBREE &&

View File

@ -122,7 +122,8 @@ bool OneapiDevice::check_peer_access(Device * /*peer_device*/)
bool OneapiDevice::can_use_hardware_raytracing_for_features(uint requested_features) const
{
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1. */
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
*/
# if defined(RTC_VERSION) && RTC_VERSION < 40100
return !(requested_features & (KERNEL_FEATURE_MNEE | KERNEL_FEATURE_NODE_RAYTRACE));
# else
@ -135,14 +136,14 @@ BVHLayoutMask OneapiDevice::get_bvh_layout_mask(uint requested_features) const
{
return (use_hardware_raytracing &&
can_use_hardware_raytracing_for_features(requested_features)) ?
BVH_LAYOUT_EMBREE :
BVH_LAYOUT_EMBREEGPU :
BVH_LAYOUT_BVH2;
}
# ifdef WITH_EMBREE_GPU
void OneapiDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREE) {
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREEGPU) {
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
if (refit) {
bvh_embree->refit(progress);
@ -435,7 +436,7 @@ void OneapiDevice::const_copy_to(const char *name, void *host, size_t size)
<< string_human_readable_size(size) << ")";
# ifdef WITH_EMBREE_GPU
if (strcmp(name, "data") == 0) {
if (embree_scene != nullptr && strcmp(name, "data") == 0) {
assert(size <= sizeof(KernelData));
/* Update scene handle(since it is different for each device on multi devices) */

View File

@ -15,6 +15,8 @@ struct GuidingParams {
bool use_volume_guiding = false;
GuidingDistributionType type = GUIDING_TYPE_PARALLAX_AWARE_VMM;
GuidingDirectionalSamplingType sampling_type = GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS;
float roughness_threshold = 0.05f;
int training_samples = 128;
bool deterministic = false;
@ -24,7 +26,9 @@ struct GuidingParams {
{
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
(sampling_type == other.sampling_type) &&
(training_samples == other.training_samples) &&
(roughness_threshold == other.roughness_threshold) &&
(deterministic == other.deterministic));
}
};

View File

@ -207,6 +207,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, direct_light_sampling_type)
KERNEL_STRUCT_MEMBER(integrator, float, surface_guiding_probability)
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
KERNEL_STRUCT_MEMBER(integrator, int, guiding_distribution_type)
KERNEL_STRUCT_MEMBER(integrator, int, guiding_directional_sampling_type)
KERNEL_STRUCT_MEMBER(integrator, float, guiding_roughness_threshold)
KERNEL_STRUCT_MEMBER(integrator, int, use_guiding)
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
@ -216,6 +218,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
/* Padding. */
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
KERNEL_STRUCT_MEMBER(integrator, int, pad3)
KERNEL_STRUCT_END(KernelIntegrator)
/* SVM. For shader specialization. */

View File

@ -432,7 +432,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
}
ccl_gpu_kernel_postfix
/* oneAPI verion needs the local_mem accessor in the arguments. */
/* oneAPI Verizon needs the local_mem accessor in the arguments. */
#ifdef __KERNEL_ONEAPI__
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_bucket_pass,
@ -489,7 +489,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
}
ccl_gpu_kernel_postfix
/* oneAPI verion needs the local_mem accessor in the arguments. */
/* oneAPI version needs the local_mem accessor in the arguments. */
#ifdef __KERNEL_ONEAPI__
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
ccl_gpu_kernel_signature(integrator_sort_write_pass,

View File

@ -109,7 +109,7 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue,
assert(queue);
(void)kernel_global_size;
const static size_t preferred_work_group_size_intersect_shading = 32;
/* Shader evalutation kernels seems to use some amount of shared memory, so better
/* Shader evaluation kernels seems to use some amount of shared memory, so better
* to avoid usage of maximum work group sizes for them. */
const static size_t preferred_work_group_size_shader_evaluation = 256;
const static size_t preferred_work_group_size_default = 1024;
@ -196,7 +196,7 @@ bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
bool oneapi_kernel_is_compatible_with_hardware_raytracing(const std::string &kernel_name)
{
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1.
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
*/
# if defined(RTC_VERSION) && RTC_VERSION < 40100
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE)) ==

View File

@ -7,10 +7,66 @@
#include "kernel/closure/bsdf.h"
#include "kernel/film/write.h"
#if OPENPGL_VERSION_MINOR >= 5
# define RIS_INCOMING_RADIANCE
#endif
CCL_NAMESPACE_BEGIN
/* Utilities. */
struct GuidingRISSample {
float3 rand;
float2 sampled_roughness;
float eta{1.0f};
int label;
float3 wo;
float bsdf_pdf{0.0f};
float guide_pdf{0.0f};
float ris_target{0.0f};
float ris_pdf{0.0f};
float ris_weight{0.0f};
#ifdef RIS_INCOMING_RADIANCE
float incoming_radiance_pdf{0.0f};
#else
float cosine{0.0f};
#endif
BsdfEval bsdf_eval;
float avg_bsdf_eval{0.0f};
Spectrum eval{zero_spectrum()};
};
ccl_device_forceinline bool calculate_ris_target(ccl_private GuidingRISSample *ris_sample,
ccl_private const float guiding_sampling_prob)
{
#if defined(__PATH_GUIDING__)
const float pi_factor = 2.0f;
if (ris_sample->avg_bsdf_eval > 0.0f && ris_sample->bsdf_pdf > 1e-10f &&
ris_sample->guide_pdf > 0.0f)
{
# ifdef RIS_INCOMING_RADIANCE
ris_sample->ris_target = (ris_sample->avg_bsdf_eval *
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
(guiding_sampling_prob * ris_sample->incoming_radiance_pdf))));
# else
ris_sample->ris_target = (ris_sample->avg_bsdf_eval / ris_sample->cosine *
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
(guiding_sampling_prob * ris_sample->guide_pdf))));
# endif
ris_sample->ris_pdf = (0.5f * (ris_sample->bsdf_pdf + ris_sample->guide_pdf));
ris_sample->ris_weight = ris_sample->ris_target / ris_sample->ris_pdf;
return true;
}
ris_sample->ris_target = 0.0f;
ris_sample->ris_pdf = 0.0f;
return false;
#else
return false;
#endif
}
#if defined(__PATH_GUIDING__)
static pgl_vec3f guiding_vec3f(const float3 v)
{
@ -241,7 +297,7 @@ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
openpgl::cpp::SetPDFDirectionIn(state->guiding.path_segment, pdf);
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
openpgl::cpp::SetIsDelta(state->guiding.path_segment, false);
openpgl::cpp::SetEta(state->guiding.path_segment, 1.f);
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0f);
openpgl::cpp::SetRoughness(state->guiding.path_segment, roughness);
#endif
}
@ -259,11 +315,11 @@ ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
if (state->guiding.path_segment) {
// TODO (sherholz): need to find a better way to avoid this check
if ((transmittance_weight[0] < 0.f || !std::isfinite(transmittance_weight[0]) ||
if ((transmittance_weight[0] < 0.0f || !std::isfinite(transmittance_weight[0]) ||
std::isnan(transmittance_weight[0])) ||
(transmittance_weight[1] < 0.f || !std::isfinite(transmittance_weight[1]) ||
(transmittance_weight[1] < 0.0f || !std::isfinite(transmittance_weight[1]) ||
std::isnan(transmittance_weight[1])) ||
(transmittance_weight[2] < 0.f || !std::isfinite(transmittance_weight[2]) ||
(transmittance_weight[2] < 0.0f || !std::isfinite(transmittance_weight[2]) ||
std::isnan(transmittance_weight[2])))
{
}
@ -438,7 +494,7 @@ ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
sum_sample_weight += sc->sample_weight;
}
avg_roughness = avg_roughness > 0.f ? avg_roughness / sum_sample_weight : 0.f;
avg_roughness = avg_roughness > 0.0f ? avg_roughness / sum_sample_weight : 0.0f;
film_write_pass_float(buffer + kernel_data.film.pass_guiding_avg_roughness, avg_roughness);
}
@ -498,6 +554,17 @@ ccl_device_forceinline float guiding_bsdf_pdf(KernelGlobals kg,
#endif
}
ccl_device_forceinline float guiding_surface_incoming_radiance_pdf(KernelGlobals kg,
IntegratorState state,
const float3 wo)
{
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4 && OPENPGL_VERSION_MINOR >= 5
return kg->opgl_surface_sampling_distribution->IncomingRadiancePDF(guiding_vec3f(wo));
#else
return 0.0f;
#endif
}
/* Guided Volume Phases */
ccl_device_forceinline bool guiding_phase_init(KernelGlobals kg,

View File

@ -372,6 +372,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
float2 bsdf_sampled_roughness = make_float2(1.0f, 1.0f);
float bsdf_eta = 1.0f;
float mis_pdf = 1.0f;
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
if (kernel_data.integrator.use_surface_guiding) {
@ -383,9 +384,11 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
&bsdf_eval,
&bsdf_wo,
&bsdf_pdf,
&mis_pdf,
&unguided_bsdf_pdf,
&bsdf_sampled_roughness,
&bsdf_eta);
&bsdf_eta,
rng_state);
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
return LABEL_NONE;
@ -410,7 +413,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
return LABEL_NONE;
}
mis_pdf = bsdf_pdf;
unguided_bsdf_pdf = bsdf_pdf;
}
@ -445,7 +448,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
/* Update path state */
if (!(label & LABEL_TRANSPARENT)) {
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = mis_pdf;
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->N;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));

View File

@ -24,6 +24,28 @@ CCL_NAMESPACE_BEGIN
/* Guiding */
#ifdef __PATH_GUIDING__
ccl_device float surface_shader_average_sample_weight_squared_roughness(
ccl_private const ShaderData *sd)
{
float avg_squared_roughness = 0.0f;
float sum_sample_weight = 0.0f;
for (int i = 0; i < sd->num_closure; i++) {
ccl_private const ShaderClosure *sc = &sd->closure[i];
if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
continue;
}
avg_squared_roughness += sc->sample_weight * bsdf_get_specular_roughness_squared(sc);
sum_sample_weight += sc->sample_weight;
}
avg_squared_roughness = avg_squared_roughness > 0.0f ?
avg_squared_roughness / sum_sample_weight :
0.0f;
return avg_squared_roughness;
}
ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
@ -36,6 +58,9 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
}
const float surface_guiding_probability = kernel_data.integrator.surface_guiding_probability;
const int guiding_directional_sampling_type =
kernel_data.integrator.guiding_directional_sampling_type;
const float guiding_roughness_threshold = kernel_data.integrator.guiding_roughness_threshold;
float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING);
/* Compute proportion of diffuse BSDF and BSSRDFs. */
@ -43,6 +68,8 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
float bssrdf_sampling_fraction = 0.0f;
float bsdf_bssrdf_sampling_sum = 0.0f;
bool fully_opaque = true;
for (int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
@ -56,6 +83,10 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
if (CLOSURE_IS_BSSRDF(sc->type)) {
bssrdf_sampling_fraction += sweight;
}
if (CLOSURE_IS_BSDF_TRANSPARENT(sc->type) || CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) {
fully_opaque = false;
}
}
}
@ -64,17 +95,36 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
bssrdf_sampling_fraction /= bsdf_bssrdf_sampling_sum;
}
/* Init guiding (diffuse BSDFs only for now). */
if (!(diffuse_sampling_fraction > 0.0f &&
guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding)))
/* Init guiding */
/* The the roughness because the function returns alpha.x * alpha.y. In addition alpha is squared
* again */
float avg_roughness = surface_shader_average_sample_weight_squared_roughness(sd);
avg_roughness = safe_sqrtf(avg_roughness);
if (!fully_opaque || avg_roughness < guiding_roughness_threshold ||
((guiding_directional_sampling_type == GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS) &&
(diffuse_sampling_fraction <= 0.0f)) ||
!guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding))
{
state->guiding.use_surface_guiding = false;
state->guiding.surface_guiding_sampling_prob = 0.0f;
return;
}
state->guiding.use_surface_guiding = true;
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
diffuse_sampling_fraction;
if (kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS)
{
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
diffuse_sampling_fraction;
}
else if (kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
{
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability;
}
else { // GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability * avg_roughness;
}
state->guiding.bssrdf_sampling_prob = bssrdf_sampling_fraction;
state->guiding.sample_surface_guiding_rand = rand_bsdf_guiding;
@ -325,12 +375,20 @@ ccl_device_inline
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
if (state->guiding.use_surface_guiding) {
if (pdf > 0.0f && state->guiding.use_surface_guiding) {
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
const float guide_pdf = guiding_bsdf_pdf(kg, state, wo);
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
(1.0f - guiding_sampling_prob) * pdf;
if (kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
{
pdf = (0.5f * guide_pdf * (1.0f - bssrdf_sampling_prob)) + 0.5f * pdf;
}
else {
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
(1.0f - guiding_sampling_prob) * pdf;
}
}
#endif
@ -406,17 +464,17 @@ surface_shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict s
/* Sample direction for picked BSDF, and return evaluation and pdf for all
* BSDFs combined using MIS. */
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 rand_bsdf,
ccl_private BsdfEval *bsdf_eval,
ccl_private float3 *wo,
ccl_private float *bsdf_pdf,
ccl_private float *unguided_bsdf_pdf,
ccl_private float2 *sampled_rougness,
ccl_private float *eta)
ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 rand_bsdf,
ccl_private BsdfEval *bsdf_eval,
ccl_private float3 *wo,
ccl_private float *bsdf_pdf,
ccl_private float *unguided_bsdf_pdf,
ccl_private float2 *sampled_rougness,
ccl_private float *eta)
{
/* BSSRDF should already have been handled elsewhere. */
kernel_assert(CLOSURE_IS_BSDF(sc->type));
@ -478,6 +536,10 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
label = bsdf_label(kg, &sd->closure[idx], *wo);
}
else {
*bsdf_pdf = 0.0f;
*unguided_bsdf_pdf = 0.0f;
}
}
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
@ -499,6 +561,9 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
sampled_rougness,
eta);
# if 0
// Code path to validate the estimation of the label, sampled roughness and eta
// This should be activated from time to time when the BSDFs change to check if everything
// is still working correctly.
if (*unguided_bsdf_pdf > 0.0f) {
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
}
@ -529,6 +594,309 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
return label;
}
ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 rand_bsdf,
ccl_private const RNGState *rng_state,
ccl_private BsdfEval *bsdf_eval,
ccl_private float3 *wo,
ccl_private float *bsdf_pdf,
ccl_private float *mis_pdf,
ccl_private float *unguided_bsdf_pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
{
/* BSSRDF should already have been handled elsewhere. */
kernel_assert(CLOSURE_IS_BSDF(sc->type));
const bool use_surface_guiding = state->guiding.use_surface_guiding;
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
/* Decide between sampling guiding distribution and BSDF. */
float rand_bsdf_guiding = state->guiding.sample_surface_guiding_rand;
/* Initialize to zero. */
int label = LABEL_NONE;
Spectrum eval = zero_spectrum();
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
*unguided_bsdf_pdf = 0.0f;
float guide_pdf = 0.0f;
if (use_surface_guiding && guiding_sampling_prob > 0.0f) {
/* Performing guided sampling using RIS */
// selected RIS candidate
int ris_idx = 0;
// meta data for the two RIS candidates
GuidingRISSample ris_samples[2];
ris_samples[0].rand = rand_bsdf;
ris_samples[1].rand = path_state_rng_3D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_0);
// ----------------------------------------------------
// generate the first RIS candidate using a BSDF sample
// ----------------------------------------------------
ris_samples[0].label = bsdf_sample(kg,
sd,
sc,
INTEGRATOR_STATE(state, path, flag),
ris_samples[0].rand,
&ris_samples[0].eval,
&ris_samples[0].wo,
&ris_samples[0].bsdf_pdf,
&ris_samples[0].sampled_roughness,
&ris_samples[0].eta);
bsdf_eval_init(&ris_samples[0].bsdf_eval, sc->type, ris_samples[0].eval * sc->weight);
if (ris_samples[0].bsdf_pdf > 0.0f) {
if (sd->num_closure > 1) {
float sweight = sc->sample_weight;
ris_samples[0].bsdf_pdf = _surface_shader_bsdf_eval_mis(kg,
sd,
ris_samples[0].wo,
sc,
&ris_samples[0].bsdf_eval,
(ris_samples[0].bsdf_pdf) *
sweight,
sweight,
0);
kernel_assert(reduce_min(bsdf_eval_sum(&ris_samples[0].bsdf_eval)) >= 0.0f);
}
ris_samples[0].avg_bsdf_eval = average(ris_samples[0].bsdf_eval.sum);
ris_samples[0].guide_pdf = guiding_bsdf_pdf(kg, state, ris_samples[0].wo);
ris_samples[0].guide_pdf *= (1.0f - bssrdf_sampling_prob);
# ifdef RIS_INCOMING_RADIANCE
ris_samples[0].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
kg, state, ris_samples[0].wo);
# else
ris_samples[0].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[0].wo)));
# endif
ris_samples[0].bsdf_pdf = max(0.0f, ris_samples[0].bsdf_pdf);
}
// ------------------------------------------------------------------------------
// generate the second RIS candidate using a sample from the guiding distribution
// ------------------------------------------------------------------------------
float unguided_bsdf_pdfs[MAX_CLOSURE];
bsdf_eval_init(&ris_samples[1].bsdf_eval, CLOSURE_NONE_ID, eval);
ris_samples[1].guide_pdf = guiding_bsdf_sample(
kg, state, float3_to_float2(ris_samples[1].rand), &ris_samples[1].wo);
ris_samples[1].guide_pdf *= (1.0f - bssrdf_sampling_prob);
# ifdef RIS_INCOMING_RADIANCE
ris_samples[1].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
kg, state, ris_samples[1].wo);
# else
ris_samples[1].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[1].wo)));
# endif
ris_samples[1].bsdf_pdf = surface_shader_bsdf_eval_pdfs(
kg, sd, ris_samples[1].wo, &ris_samples[1].bsdf_eval, unguided_bsdf_pdfs, 0);
ris_samples[1].label = ris_samples[0].label;
ris_samples[1].avg_bsdf_eval = average(ris_samples[1].bsdf_eval.sum);
ris_samples[1].bsdf_pdf = max(0.0f, ris_samples[1].bsdf_pdf);
// ------------------------------------------------------------------------------
// calculate the RIS target functions for each RIS candidate
// ------------------------------------------------------------------------------
int num_ris_candidates = 0;
float sum_ris_weights = 0.0f;
if (calculate_ris_target(&ris_samples[0], guiding_sampling_prob)) {
sum_ris_weights += ris_samples[0].ris_weight;
num_ris_candidates++;
}
kernel_assert(ris_samples[0].ris_weight >= 0.0f);
kernel_assert(sum_ris_weights >= 0.0f);
if (calculate_ris_target(&ris_samples[1], guiding_sampling_prob)) {
sum_ris_weights += ris_samples[1].ris_weight;
num_ris_candidates++;
}
kernel_assert(ris_samples[1].ris_weight >= 0.0f);
kernel_assert(sum_ris_weights >= 0.0f);
// ------------------------------------------------------------------------------
// Sample/Select a sample from the RIS candidates proportional to the target
// ------------------------------------------------------------------------------
if (num_ris_candidates == 0 || !(sum_ris_weights > 1e-10f)) {
*bsdf_pdf = 0.0f;
*mis_pdf = 0.0f;
return label;
}
float rand_ris_select = rand_bsdf_guiding * sum_ris_weights;
float sum_ris = 0.0f;
for (int i = 0; i < 2; i++) {
sum_ris += ris_samples[i].ris_weight;
if (rand_ris_select <= sum_ris) {
ris_idx = i;
break;
}
}
kernel_assert(sum_ris >= 0.0f);
kernel_assert(ris_idx < 2);
// ------------------------------------------------------------------------------
// Fill in the sample data for the selected RIS candidate
// ------------------------------------------------------------------------------
guide_pdf = ris_samples[ris_idx].ris_target * (2.0f / sum_ris_weights);
*unguided_bsdf_pdf = ris_samples[ris_idx].bsdf_pdf;
*mis_pdf = 0.5f * (ris_samples[ris_idx].bsdf_pdf + ris_samples[ris_idx].guide_pdf);
*bsdf_pdf = guide_pdf;
*wo = ris_samples[ris_idx].wo;
label = ris_samples[ris_idx].label;
*sampled_roughness = ris_samples[ris_idx].sampled_roughness;
*eta = ris_samples[ris_idx].eta;
*bsdf_eval = ris_samples[ris_idx].bsdf_eval;
kernel_assert(isfinite_safe(guide_pdf));
kernel_assert(isfinite_safe(*bsdf_pdf));
if (!(*bsdf_pdf > 1e-10f)) {
*bsdf_pdf = 0.0f;
*mis_pdf = 0.0f;
return label;
}
kernel_assert(*bsdf_pdf > 0.0f);
kernel_assert(*bsdf_pdf >= 1e-20f);
kernel_assert(guide_pdf >= 0.0f);
/// select label sampled_roughness and eta
if (ris_idx == 1 && ris_samples[1].bsdf_pdf > 0.0f) {
float rnd = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_1);
float sum_pdfs = 0.0f;
int idx = -1;
for (int i = 0; i < sd->num_closure; i++) {
sum_pdfs += unguided_bsdf_pdfs[i];
if (rnd <= sum_pdfs) {
idx = i;
break;
}
}
// kernel_assert(idx >= 0);
/* Set the default idx to the last in the list.
* in case of numerical problems and rand_bsdf_guiding is just >=1.0f and
* the sum of all unguided_bsdf_pdfs is just < 1.0f. */
idx = (rnd > sum_pdfs) ? sd->num_closure - 1 : idx;
label = bsdf_label(kg, &sd->closure[idx], *wo);
bsdf_roughness_eta(kg, &sd->closure[idx], sampled_roughness, eta);
}
kernel_assert(isfinite_safe(*bsdf_pdf));
kernel_assert(*bsdf_pdf >= 0.0f);
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
}
else {
/* Sample BSDF. */
*bsdf_pdf = 0.0f;
label = bsdf_sample(kg,
sd,
sc,
INTEGRATOR_STATE(state, path, flag),
rand_bsdf,
&eval,
wo,
unguided_bsdf_pdf,
sampled_roughness,
eta);
# if 0
// Code path to validate the estimation of the label, sampled roughness and eta
// This should be activated from time to time when the BSDFs change to check if everything
// is still working correctly.
if (*unguided_bsdf_pdf > 0.0f) {
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
}
# endif
if (*unguided_bsdf_pdf != 0.0f) {
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
if (sd->num_closure > 1) {
float sweight = sc->sample_weight;
*unguided_bsdf_pdf = _surface_shader_bsdf_eval_mis(
kg, sd, *wo, sc, bsdf_eval, (*unguided_bsdf_pdf) * sweight, sweight, 0);
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
}
*bsdf_pdf = *unguided_bsdf_pdf;
*mis_pdf = *bsdf_pdf;
}
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
}
return label;
}
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 rand_bsdf,
ccl_private BsdfEval *bsdf_eval,
ccl_private float3 *wo,
ccl_private float *bsdf_pdf,
ccl_private float *mis_pdf,
ccl_private float *unguided_bsdf_pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta,
ccl_private const RNGState *rng_state)
{
int label;
if (kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS ||
kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS)
{
label = surface_shader_bsdf_guided_sample_closure_mis(kg,
state,
sd,
sc,
rand_bsdf,
bsdf_eval,
wo,
bsdf_pdf,
unguided_bsdf_pdf,
sampled_roughness,
eta);
*mis_pdf = (*unguided_bsdf_pdf > 0.0f) ? *bsdf_pdf : 0.0f;
}
else if (kernel_data.integrator.guiding_directional_sampling_type ==
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
{
label = surface_shader_bsdf_guided_sample_closure_ris(kg,
state,
sd,
sc,
rand_bsdf,
rng_state,
bsdf_eval,
wo,
bsdf_pdf,
mis_pdf,
unguided_bsdf_pdf,
sampled_roughness,
eta);
}
if (!(*unguided_bsdf_pdf > 0.0f)) {
*bsdf_pdf = 0.0f;
*mis_pdf = 0.0f;
}
return label;
}
#endif
/* Sample direction for picked BSDF, and return evaluation and pdf for all

View File

@ -163,6 +163,11 @@ enum PathTraceDimension {
PRNG_SURFACE_AO = 4,
PRNG_SURFACE_BEVEL = 5,
PRNG_SURFACE_BSDF_GUIDING = 6,
/* Guiding RIS */
PRNG_SURFACE_RIS_GUIDING_0 = 10,
PRNG_SURFACE_RIS_GUIDING_1 = 11,
/* Volume */
PRNG_VOLUME_PHASE = 3,
PRNG_VOLUME_PHASE_CHANNEL = 4,
@ -506,6 +511,16 @@ typedef enum GuidingDistributionType {
GUIDING_NUM_TYPES,
} GuidingDistributionType;
/* Guiding Directional Sampling Type */
typedef enum GuidingDirectionalSamplingType {
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS = 0,
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS = 1,
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS = 2,
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
} GuidingDirectionalSamplingType;
/* Camera Type */
enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
@ -1172,11 +1187,16 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_HIPRT = (1 << 8),
BVH_LAYOUT_MULTI_HIPRT = (1 << 9),
BVH_LAYOUT_MULTI_HIPRT_EMBREE = (1 << 10),
BVH_LAYOUT_EMBREEGPU = (1 << 11),
BVH_LAYOUT_MULTI_EMBREEGPU = (1 << 12),
BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE = (1 << 13),
/* Default BVH layout to use for CPU. */
BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX | BVH_LAYOUT_METAL |
BVH_LAYOUT_HIPRT | BVH_LAYOUT_MULTI_HIPRT | BVH_LAYOUT_MULTI_HIPRT_EMBREE,
BVH_LAYOUT_HIPRT | BVH_LAYOUT_MULTI_HIPRT | BVH_LAYOUT_MULTI_HIPRT_EMBREE |
BVH_LAYOUT_EMBREEGPU | BVH_LAYOUT_MULTI_EMBREEGPU |
BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE,
} KernelBVHLayout;
/* Specialized struct that can become constants in dynamic compilation. */

View File

@ -116,7 +116,8 @@ bool Geometry::need_build_bvh(BVHLayout layout) const
layout == BVH_LAYOUT_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
layout == BVH_LAYOUT_HIPRT || layout == BVH_LAYOUT_MULTI_HIPRT ||
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE;
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE || layout == BVH_LAYOUT_EMBREEGPU ||
layout == BVH_LAYOUT_MULTI_EMBREEGPU || layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
}
bool Geometry::is_instanced() const

View File

@ -60,10 +60,17 @@ NODE_DEFINE(Integrator)
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
static NodeEnum guiding_ditribution_enum;
guiding_ditribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
guiding_ditribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
guiding_ditribution_enum.insert("VMM", GUIDING_TYPE_VMM);
static NodeEnum guiding_distribution_enum;
guiding_distribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
guiding_distribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
guiding_distribution_enum.insert("VMM", GUIDING_TYPE_VMM);
static NodeEnum guiding_directional_sampling_type_enum;
guiding_directional_sampling_type_enum.insert("MIS",
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS);
guiding_directional_sampling_type_enum.insert("RIS", GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
guiding_directional_sampling_type_enum.insert("ROUGHNESS",
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS);
SOCKET_BOOLEAN(use_guiding, "Guiding", false);
SOCKET_BOOLEAN(deterministic_guiding, "Deterministic Guiding", true);
@ -76,8 +83,13 @@ NODE_DEFINE(Integrator)
SOCKET_BOOLEAN(use_guiding_mis_weights, "Use MIS Weights", true);
SOCKET_ENUM(guiding_distribution_type,
"Guiding Distribution Type",
guiding_ditribution_enum,
guiding_distribution_enum,
GUIDING_TYPE_PARALLAX_AWARE_VMM);
SOCKET_ENUM(guiding_directional_sampling_type,
"Guiding Directional Sampling Type",
guiding_directional_sampling_type_enum,
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
SOCKET_FLOAT(guiding_roughness_threshold, "Guiding Roughness Threshold", 0.05f);
SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
@ -239,6 +251,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->use_guiding_direct_light = use_guiding_direct_light;
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
kintegrator->guiding_distribution_type = guiding_params.type;
kintegrator->guiding_directional_sampling_type = guiding_params.sampling_type;
kintegrator->guiding_roughness_threshold = guiding_params.roughness_threshold;
kintegrator->seed = seed;
@ -409,7 +423,9 @@ GuidingParams Integrator::get_guiding_params(const Device *device) const
guiding_params.type = guiding_distribution_type;
guiding_params.training_samples = guiding_training_samples;
guiding_params.deterministic = deterministic_guiding;
guiding_params.sampling_type = guiding_directional_sampling_type;
// In Blender/Cycles the user set roughness is squared to behave more linear.
guiding_params.roughness_threshold = guiding_roughness_threshold * guiding_roughness_threshold;
return guiding_params;
}
CCL_NAMESPACE_END

View File

@ -54,6 +54,8 @@ class Integrator : public Node {
NODE_SOCKET_API(bool, use_guiding_direct_light);
NODE_SOCKET_API(bool, use_guiding_mis_weights);
NODE_SOCKET_API(GuidingDistributionType, guiding_distribution_type);
NODE_SOCKET_API(GuidingDirectionalSamplingType, guiding_directional_sampling_type);
NODE_SOCKET_API(float, guiding_roughness_threshold);
NODE_SOCKET_API(bool, caustics_reflective)
NODE_SOCKET_API(bool, caustics_refractive)

View File

@ -73,6 +73,17 @@ struct WGL_XDG_Decor_Window {
struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
struct xdg_toplevel *toplevel = nullptr;
enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0;
/**
* Defer calling #xdg_surface_ack_configure.
* \note Accessing the members must lock on `win->frame_pending_mutex`.
*/
struct {
/** When set, ACK configure is expected. */
bool ack_configure = false;
/** The serial to pass to ACK configure. */
uint32_t ack_configure_serial = 0;
} pending;
};
static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
@ -745,6 +756,18 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
wl_surface_set_buffer_scale(win->wl_surface, win->frame.buffer_scale);
}
if (win->xdg_decor) {
WGL_XDG_Decor_Window &decor = *win->xdg_decor;
if (decor.pending.ack_configure) {
xdg_surface_ack_configure(decor.surface, decor.pending.ack_configure_serial);
/* The XDG spec states a commit event is required after ACK configure. */
surface_needs_commit = true;
decor.pending.ack_configure = false;
decor.pending.ack_configure_serial = 0;
}
}
if (surface_needs_commit) {
#ifdef USE_EVENT_BACKGROUND_THREAD
/* Postponing the commit avoids flickering when moving between monitors of different scale. */
@ -1179,6 +1202,12 @@ static void xdg_surface_handle_configure(void *data,
}
CLOG_INFO(LOG, 2, "configure");
#ifdef USE_EVENT_BACKGROUND_THREAD
std::lock_guard lock_frame_guard{static_cast<GWL_Window *>(data)->frame_pending_mutex};
#endif
win->xdg_decor->pending.ack_configure = true;
win->xdg_decor->pending.ack_configure_serial = serial;
#ifdef USE_EVENT_BACKGROUND_THREAD
GHOST_SystemWayland *system = win->ghost_system;
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
@ -1190,10 +1219,8 @@ static void xdg_surface_handle_configure(void *data,
else
#endif
{
gwl_window_frame_update_from_pending(win);
gwl_window_frame_update_from_pending_no_lock(win);
}
xdg_surface_ack_configure(xdg_surface, serial);
}
static const xdg_surface_listener xdg_surface_listener = {

View File

@ -40,7 +40,7 @@
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #23:Greek (Ελληνικά):el_GR
35:Esperanto (Esperanto):eo
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #36:Spanish from Spain (Español de España):es_ES
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eestlane):et_EE
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eesti keel):et_EE
42:Basque (Euskara):eu_EU
26:Persian (ﯽﺳﺭﺎﻓ):fa_IR
6:Finnish (Suomi):fi_FI

View File

@ -68,7 +68,7 @@ LANGUAGES = (
(32, "Brazilian Portuguese (Português do Brasil)", "pt_BR"),
# Using the utf8 flipped form of Hebrew (עִבְרִית)).
(33, "Hebrew (תירִבְעִ)", "he_IL"),
(34, "Estonian (Eestlane)", "et_EE"),
(34, "Estonian (Eesti keel)", "et_EE"),
(35, "Esperanto (Esperanto)", "eo"),
(36, "Spanish from Spain (Español de España)", "es_ES"),
(37, "Amharic (አማርኛ)", "am_ET"),
@ -206,7 +206,7 @@ _str_base = (
r"(?:(?!<\\)(?:\\\\)*\\(?=(?P={_}2)))|"
# The most common case.
".(?!(?P={_}2))"
")+.)" # Don't forget the last char!
")*.)" # Don't forget the last char!
"(?P={_}2)" # And closing quote.
)
str_clean_re = _str_base.format(_="g", capt="P<clean>")
@ -257,7 +257,8 @@ PYGETTEXT_KEYWORDS = (() +
for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
# Node socket declarations: contextless names
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)").format(it)
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)"
r"(?![^;]*\.translation_context\()").format(it)
for it in ("add_input", "add_output")) +
# Node socket declarations: names with contexts

View File

@ -250,6 +250,15 @@ class Prefs(bpy.types.KeyConfigPreferences):
update=update_fn,
)
use_transform_navigation: BoolProperty(
name="Navigate during Transform",
description=(
"Enable view navigation while using transform operators. "
"Proportional Influence, Automatic Constraints and Auto IK Chain Length shortcuts will require holding Alt key"),
default=False,
update=update_fn,
)
def draw(self, layout):
from bpy import context
@ -313,6 +322,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
sub.prop(self, "use_v3d_tab_menu")
sub.prop(self, "use_pie_click_drag")
sub.prop(self, "use_v3d_shade_ex_pie")
sub.prop(self, "use_transform_navigation")
# File Browser settings.
col = layout.column()
@ -365,6 +375,7 @@ def load():
use_alt_click_leader=kc_prefs.use_alt_click_leader,
use_pie_click_drag=kc_prefs.use_pie_click_drag,
use_file_single_click=kc_prefs.use_file_single_click,
use_transform_navigation=kc_prefs.use_transform_navigation,
),
)

View File

@ -93,6 +93,8 @@ class Params:
# Since this means with RMB select enabled in edit-mode for e.g.
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
"tool_maybe_tweak_event",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
"use_transform_navigation",
)
def __init__(
@ -119,6 +121,7 @@ class Params:
use_file_single_click=False,
v3d_tilde_action='VIEW',
v3d_alt_mmb_drag_action='RELATIVE',
use_transform_navigation=False,
):
from sys import platform
self.apple = (platform == 'darwin')
@ -209,6 +212,7 @@ class Params:
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
self.tool_tweak_event = {"type": self.tool_mouse, "value": 'CLICK_DRAG'}
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
self.use_transform_navigation = use_transform_navigation
# ------------------------------------------------------------------------------
@ -1312,7 +1316,7 @@ def km_uv_editor(params):
{"properties": [("extend", True)]}),
])
# 3D cursor
# 2D cursor
if params.cursor_tweak_event:
items.extend([
("uv.cursor_set", params.cursor_set_event, None),
@ -1581,13 +1585,16 @@ def km_view3d(params):
# Transform.
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
op_tool_optional(
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.move"), params),
op_tool_optional(
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.rotate"), params),
op_tool_optional(
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
("transform.resize", {"type": 'S', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.scale"), params),
op_tool_optional(
("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
@ -2497,7 +2504,7 @@ def km_nla_generic(_params):
sidebar_key={"type": 'N', "value": 'PRESS'},
),
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS'},
{"properties": [("use_upper_stack_evaluation", True)]}),
{"properties": [("use_upper_stack_evaluation", False)]}),
("nla.tweakmode_exit", {"type": 'TAB', "value": 'PRESS'}, None),
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS', "shift": True},
{"properties": [("isolate_action", True)]}),
@ -3470,7 +3477,6 @@ def km_animation_channels(params):
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("children_only", True)]}),
# Rename.
("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
# Select keys.
("anim.channel_select_keys", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
@ -4681,10 +4687,13 @@ def km_paint_curve(params):
("paintcurve.delete_point", {"type": 'DEL', "value": 'PRESS'}, None),
("paintcurve.draw", {"type": 'RET', "value": 'PRESS'}, None),
("paintcurve.draw", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
("transform.resize", {"type": 'S', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
])
return keymap
@ -5844,7 +5853,7 @@ def km_eyedropper_colorramp_pointsampling_map(_params):
return keymap
def km_transform_modal_map(_params):
def km_transform_modal_map(params):
items = []
keymap = (
"Transform Modal Map",
@ -5884,24 +5893,24 @@ def km_transform_modal_map(_params):
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("INSERTOFS_TOGGLE_DIR", {"type": 'T', "value": 'PRESS'}, None),
("NODE_ATTACH_ON", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
("NODE_ATTACH_OFF", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY', "alt": params.use_transform_navigation}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True, "alt": params.use_transform_navigation}, None),
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
])

View File

@ -257,6 +257,7 @@ class TIME_PT_playback(TimelinePanelButtons, Panel):
col.prop(screen, "use_play_clip_editors", text="Movie Clip Editor")
col.prop(screen, "use_play_node_editors", text="Node Editors")
col.prop(screen, "use_play_sequence_editors", text="Video Sequencer")
col.prop(screen, "use_play_spreadsheet_editors")
col = layout.column(heading="Show")
col.prop(scene, "show_subframe", text="Subframes")

View File

@ -1038,10 +1038,22 @@ class VIEW3D_MT_transform_base:
# TODO: get rid of the custom text strings?
def draw(self, context):
layout = self.layout
allow_navigation = getattr(
context.window_manager.keyconfigs.active.preferences,
"use_transform_navigation",
False)
layout.operator("transform.translate")
layout.operator("transform.rotate")
layout.operator("transform.resize", text="Scale")
props = layout.operator("transform.translate")
props.release_confirm = False
props.allow_navigation = allow_navigation
props = layout.operator("transform.rotate")
props.release_confirm = False
props.allow_navigation = allow_navigation
props = layout.operator("transform.resize", text="Scale")
props.release_confirm = False
props.allow_navigation = allow_navigation
layout.separator()

View File

@ -155,6 +155,17 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
bl_ui_units_x = 12
def draw(self, _context):
# layout = self.layout
pass
class VIEW3D_PT_tools_meshedit_options_transform(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Transform"
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
@classmethod
def poll(cls, context):
return context.active_object
@ -169,56 +180,47 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
ob = context.active_object
mesh = ob.data
row = layout.row(align=True, heading="Transform")
row.prop(tool_settings, "use_transform_correct_face_attributes")
col = layout.column(align=True)
col.prop(tool_settings, "use_transform_correct_face_attributes")
sub = col.column(align=True)
sub.active = tool_settings.use_transform_correct_face_attributes
sub.prop(tool_settings, "use_transform_correct_keep_connected")
col.separator()
row = layout.row(align=True)
row.active = tool_settings.use_transform_correct_face_attributes
row.prop(tool_settings, "use_transform_correct_keep_connected")
row = layout.row(align=True, heading="UVs")
row.prop(tool_settings, "use_edge_path_live_unwrap")
row = layout.row(heading="Mirror")
sub = row.row(align=True)
col = layout.column(heading="Mirror")
sub = col.row(align=True)
sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
sub.prop(mesh, "use_mirror_y", text="Y", toggle=True)
sub.prop(mesh, "use_mirror_z", text="Z", toggle=True)
row = layout.row(align=True)
row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
row.prop(mesh, "use_mirror_topology")
col = layout.column(align=True)
col.active = mesh.use_mirror_x or mesh.use_mirror_y or mesh.use_mirror_z
col.prop(mesh, "use_mirror_topology")
col.separator()
col = layout.column(align=True)
col.prop(tool_settings, "use_mesh_automerge", text="Auto Merge", toggle=False)
sub = col.column(align=True)
sub.active = tool_settings.use_mesh_automerge
sub.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
sub.prop(tool_settings, "double_threshold", text="Threshold")
class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
class VIEW3D_PT_tools_meshedit_options_uvs(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Auto Merge"
bl_label = "UVs"
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.active_object
def draw_header(self, context):
tool_settings = context.tool_settings
self.layout.use_property_split = False
self.layout.prop(tool_settings, "use_mesh_automerge",
text=self.bl_label if self.is_popover else "", toggle=False)
def draw(self, context):
layout = self.layout
layout.use_property_decorate = False
layout.use_property_split = True
tool_settings = context.tool_settings
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column(align=True)
col.active = tool_settings.use_mesh_automerge
col.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
col.prop(tool_settings, "double_threshold", text="Threshold")
layout.prop(tool_settings, "use_edge_path_live_unwrap")
# ********** default tools for editmode_armature ****************
@ -2368,7 +2370,8 @@ classes = (
VIEW3D_PT_tools_object_options,
VIEW3D_PT_tools_object_options_transform,
VIEW3D_PT_tools_meshedit_options,
VIEW3D_PT_tools_meshedit_options_automerge,
VIEW3D_PT_tools_meshedit_options_transform,
VIEW3D_PT_tools_meshedit_options_uvs,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,

View File

@ -480,7 +480,7 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
/**
* Resize the FCurve 'bezt' array to fit the given length.
*
* \param new_totvert new number of elements in the FCurve's `bezt` array.
* \param new_totvert: new number of elements in the FCurve's `bezt` array.
* Constraint: `0 <= new_totvert <= fcu->totvert`
*/
void BKE_fcurve_bezt_shrink(struct FCurve *fcu, int new_totvert);

View File

@ -311,10 +311,11 @@ void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
/**
* Like BKE_id_delete, but with extra corner-case options.
*
* \param extra_remapping_flags Additional `ID_REMAP_` flags to pass to remapping code when
* \param extra_remapping_flags: Additional `ID_REMAP_` flags to pass to remapping code when
* ensuring that deleted IDs are not used by any other ID in given `bmain`. Typical example would
* be e.g. `ID_REMAP_FORCE_UI_POINTERS`, required when default UI-handling callbacks of remapping
* code won't be working (e.g. from readfile code). */
* code won't be working (e.g. from readfile code).
*/
void BKE_id_delete_ex(struct Main *bmain, void *idv, const int extra_remapping_flags)
ATTR_NONNULL(1, 2);
/**

View File

@ -303,6 +303,27 @@ struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
*/
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
/**
* Delete a property override from the given ID \a override, if it exists.
*
* \return True when the property was found (and thus deleted), false if it wasn't found.
*/
bool BKE_lib_override_library_property_search_and_delete(struct IDOverrideLibrary *override,
const char *rna_path);
/** Change the RNA path of a library override on a property.
*
* No-op if the property override cannot be found.
*
* \param from_rna_path The RNA path of the property to change.
* \param to_rna_path The new RNA path. The library override system will copy the string to its own
* memory; the caller will retain ownership of the passed pointer.
* \return True if the property was found (and thus changed), false if it wasn't found.
*/
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *liboverride,
const char *old_rna_path,
const char *new_rna_path);
/**
* Get the RNA-property matching the \a library_prop override property. Used for UI to query
* additional data about the overridden property (e.g. UI name).

View File

@ -86,7 +86,7 @@ void normals_calc_poly_vert(Span<float3> vert_positions,
* \{ */
/**
* Combined with the automatically calculated face corner normal, this gives a dimentional
* Combined with the automatically calculated face corner normal, this gives a dimensional
* coordinate space used to convert normals between the "custom normal" #short2 representation and
* a regular #float3 format.
*/

View File

@ -19,7 +19,7 @@ struct CustomData_MeshMasks;
struct MemArena;
struct Mesh;
/* Generic ways to map some geometry elements from a source mesh to a dest one. */
/* Generic ways to map some geometry elements from a source mesh to a destination one. */
typedef struct MeshPairRemapItem {
int sources_num;
@ -33,7 +33,7 @@ typedef struct MeshPairRemapItem {
/* All mapping computing func return this. */
typedef struct MeshPairRemap {
int items_num;
MeshPairRemapItem *items; /* array, one item per dest element. */
MeshPairRemapItem *items; /* Array, one item per destination element. */
struct MemArena *mem; /* memory arena, internal use only. */
} MeshPairRemap;
@ -89,7 +89,7 @@ enum {
/* ***** Target's edges ***** */
MREMAP_MODE_EDGE = 1 << 25,
/* Source edge which both vertices are nearest of dest ones. */
/* Source edge which both vertices are nearest of destination ones. */
MREMAP_MODE_EDGE_VERT_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NEAREST,
/* Nearest source edge (using mid-point). */
@ -98,7 +98,7 @@ enum {
/* Nearest edge of nearest poly (using mid-point). */
MREMAP_MODE_EDGE_POLY_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_POLY | MREMAP_USE_NEAREST,
/* Cast a set of rays from along dest edge,
/* Cast a set of rays from along destination edge,
* interpolating its vertices' normals, and use hit source edges. */
MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NORPROJ |
MREMAP_USE_INTERP,
@ -131,10 +131,10 @@ enum {
/* Nearest source poly. */
MREMAP_MODE_POLY_NEAREST = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NEAREST,
/* Source poly from best normal-matching dest poly. */
/* Source poly from best normal-matching destination poly. */
MREMAP_MODE_POLY_NOR = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORMAL,
/* Project dest poly onto source mesh using its normal,
/* Project destination poly onto source mesh using its normal,
* and use interpolation of all intersecting source polys. */
MREMAP_MODE_POLY_POLYINTERP_PNORPROJ = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORPROJ |
MREMAP_USE_INTERP,

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2005 Blender Foundation */
* Copyright 2023 Blender Foundation */
#pragma once

View File

@ -334,7 +334,7 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings);
}
/* XXX can I reduce the number of normalisations here? */
/* XXX can I reduce the number of normalization calls here? */
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
CCGVert *v = (CCGVert *)effectedV[ptrIdx];
float *no = VERT_getNo(v, lvl);

View File

@ -641,8 +641,8 @@ static int animsys_quaternion_evaluate_fcurves(PathResolvedRNA quat_rna,
}
if (fcurve_offset < 4) {
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaterion and
* values from FCurves. This means that it's almost certainly no longer of unit length. */
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaternion
* and values from FCurves. This means that it's almost certainly no longer of unit length. */
normalize_qt(r_quaternion);
}

View File

@ -611,7 +611,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map
bool *data_dst_to_delete = nullptr;
if (!use_layers_src) {
/* No source at all, we can only delete all dest if requested... */
/* No source at all, we can only delete all destination if requested. */
if (use_delete) {
idx_dst = tot_dst;
while (idx_dst--) {
@ -1421,7 +1421,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
}
/* Check all possible data types.
* Note item mappings and dest mix weights are cached. */
* Note item mappings and destination mix weights are cached. */
for (int i = 0; i < DT_TYPE_MAX; i++) {
const int dtdata_type = 1 << i;
int cddata_type;

View File

@ -1006,7 +1006,7 @@ void BKE_main_view_layers_synced_ensure(const Main *bmain)
BKE_scene_view_layers_synced_ensure(scene);
}
/* NOTE: This is not (yet?) covered by the dirty tag and deffered re-sync system. */
/* NOTE: This is not (yet?) covered by the dirty tag and deferred re-sync system. */
BKE_layer_collection_local_sync_all(bmain);
}

View File

@ -198,8 +198,9 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
BKE_lib_override_library_init(dst_id, nullptr);
}
/* If source is already overriding data, we copy it but reuse its reference for dest ID.
* Otherwise, source is only an override template, it then becomes reference of dest ID. */
/* If source is already overriding data, we copy it but reuse its reference for destination ID.
* Otherwise, source is only an override template, it then becomes reference of destination ID.
*/
dst_id->override_library->reference = src_id->override_library->reference ?
src_id->override_library->reference :
const_cast<ID *>(src_id);
@ -1776,7 +1777,7 @@ static void lib_override_library_remap(Main *bmain,
*
* In case linked data keep being modified, these conditions may fail and the mapping may start to
* return 'wrong' results. However, this is considered as an acceptable limitation here, since this
* is mainly a 'best effort' to recover from situations that should not be hapenning in the first
* is mainly a 'best effort' to recover from situations that should not be happening in the first
* place.
*/
@ -2061,7 +2062,7 @@ static bool lib_override_library_resync(Main *bmain,
}
/* Get a mapping of all missing linked IDs that were liboverrides, to search for 'old
* liboverrides' for newly created ones that do not alredy have one, in next step. */
* liboverrides' for newly created ones that do not already have one, in next step. */
LibOverrideMissingIDsData missing_ids_data = lib_override_library_resync_build_missing_ids_data(
bmain);
@ -2638,7 +2639,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
return false;
}
/* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
/**
* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
* (typical case: Mesh object which only relationship to the rest of the liboverride hierarchy is
* though its 'parent' pointer (i.e. rest of the hierarchy has no actual relationship to this mesh
* object). Sadge.
@ -2646,7 +2648,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
* Logic and rational of this function are very similar to these of
* #lib_override_hierarchy_dependencies_recursive_tag_from, but withing specific resync context.
*
* \returns True if it finds a non-isolated 'parent' ID, false otherwise. */
* \returns True if it finds a non-isolated 'parent' ID, false otherwise.
*/
static bool lib_override_resync_tagging_finalize_recursive_check_from(
Main *bmain, ID *id, const int library_indirect_level)
{
@ -3527,6 +3530,41 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
BLI_freelistN(&op->operations);
}
bool BKE_lib_override_library_property_search_and_delete(IDOverrideLibrary *override,
const char *rna_path)
{
IDOverrideLibraryProperty *override_property = BKE_lib_override_library_property_find(override,
rna_path);
if (override_property == nullptr) {
return false;
}
BKE_lib_override_library_property_delete(override, override_property);
return true;
}
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *override,
const char *old_rna_path,
const char *new_rna_path)
{
/* Find the override property by its old RNA path. */
GHash *override_runtime = override_library_rna_path_mapping_ensure(override);
IDOverrideLibraryProperty *override_property = static_cast<IDOverrideLibraryProperty *>(
BLI_ghash_popkey(override_runtime, old_rna_path, nullptr));
if (override_property == nullptr) {
return false;
}
/* Switch over the RNA path. */
MEM_SAFE_FREE(override_property->rna_path);
override_property->rna_path = BLI_strdup(new_rna_path);
/* Put property back into the lookup mapping, using the new RNA path. */
BLI_ghash_insert(override_runtime, override_property->rna_path, override_property);
return true;
}
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{

View File

@ -257,7 +257,7 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in
BKE_object_defgroup_active_index_set(ob, active_index - 1);
}
/* remove all dverts */
/* Remove all deform-verts. */
if (BLI_listbase_is_empty(defbase)) {
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
@ -404,8 +404,8 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
dg = next_dg;
}
}
else { /* defbase is empty... */
/* remove all dverts */
else { /* `defbase` is empty. */
/* Remove all deform-verts. */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);

View File

@ -111,7 +111,8 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
*/
template<typename Callable,
BLI_ENABLE_IF((
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>))>
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>)),
BLI_ENABLE_IF((std::is_invocable_r_v<Ret, Callable, Params...>))>
FunctionRef(Callable &&callable)
: callback_(callback_fn<typename std::remove_reference_t<Callable>>),
callable_(intptr_t(&callable))

View File

@ -105,6 +105,11 @@ class IndexRange {
return a.current_ == b.current_;
}
constexpr friend int64_t operator-(const Iterator &a, const Iterator &b)
{
return a.current_ - b.current_;
}
constexpr int64_t operator*() const
{
return current_;
@ -151,6 +156,11 @@ class IndexRange {
return size_;
}
constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
/**
* Returns true if the size is zero.
*/

View File

@ -16,24 +16,30 @@
namespace blender {
/**
* If enabled, #LinearAllocator keeps track of how much memory it owns and how much it has
* allocated.
*/
// #define BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
private:
BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
Vector<void *> owned_buffers_;
Vector<Span<char>> unused_borrowed_buffers_;
Vector<void *, 2> owned_buffers_;
uintptr_t current_begin_;
uintptr_t current_end_;
#ifdef DEBUG
int64_t debug_allocated_amount_ = 0;
#endif
/* Buffers larger than that are not packed together with smaller allocations to avoid wasting
* memory. */
constexpr static inline int64_t large_buffer_threshold = 4096;
public:
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
int64_t user_requested_size_ = 0;
int64_t owned_allocation_size_ = 0;
#endif
LinearAllocator()
{
current_begin_ = 0;
@ -65,8 +71,8 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
const uintptr_t potential_allocation_end = potential_allocation_begin + size;
if (potential_allocation_end <= current_end_) {
#ifdef DEBUG
debug_allocated_amount_ += size;
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
user_requested_size_ += size;
#endif
current_begin_ = potential_allocation_end;
return reinterpret_cast<void *>(potential_allocation_begin);
@ -75,6 +81,9 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
this->allocate_new_buffer(size + alignment, alignment);
return this->allocate(size, alignment);
}
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
user_requested_size_ += size;
#endif
return this->allocator_large_buffer(size, alignment);
};
@ -189,9 +198,11 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
* Tell the allocator to use up the given memory buffer, before allocating new memory from the
* system.
*/
void provide_buffer(void *buffer, uint size)
void provide_buffer(void *buffer, const int64_t size)
{
unused_borrowed_buffers_.append(Span<char>(static_cast<char *>(buffer), size));
BLI_assert(owned_buffers_.is_empty());
current_begin_ = uintptr_t(buffer);
current_end_ = current_begin_ + size;
}
template<size_t Size, size_t Alignment>
@ -200,19 +211,28 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
this->provide_buffer(aligned_buffer.ptr(), Size);
}
/**
* This allocator takes ownership of the buffers owned by `other`. Therefor, when `other` is
* destructed, memory allocated using it is not freed.
*
* Note that the caller is responsible for making sure that buffers passed into #provide_buffer
* of `other` live at least as long as this allocator.
*/
void transfer_ownership_from(LinearAllocator<> &other)
{
owned_buffers_.extend(other.owned_buffers_);
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
user_requested_size_ += other.user_requested_size_;
owned_allocation_size_ += other.owned_allocation_size_;
#endif
other.owned_buffers_.clear();
std::destroy_at(&other);
new (&other) LinearAllocator<>();
}
private:
void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment)
{
for (int64_t i : unused_borrowed_buffers_.index_range()) {
Span<char> buffer = unused_borrowed_buffers_[i];
if (buffer.size() >= min_allocation_size) {
unused_borrowed_buffers_.remove_and_reorder(i);
current_begin_ = uintptr_t(buffer.begin());
current_end_ = uintptr_t(buffer.end());
return;
}
}
/* Possibly allocate more bytes than necessary for the current allocation. This way more small
* allocations can be packed together. Large buffers are allocated exactly to avoid wasting too
* much memory. */
@ -224,16 +244,23 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
std::max<int64_t>(size_in_bytes, grow_size));
}
void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__);
owned_buffers_.append(buffer);
void *buffer = this->allocated_owned(size_in_bytes, min_alignment);
current_begin_ = uintptr_t(buffer);
current_end_ = current_begin_ + size_in_bytes;
}
void *allocator_large_buffer(const int64_t size, const int64_t alignment)
{
return this->allocated_owned(size, alignment);
}
void *allocated_owned(const int64_t size, const int64_t alignment)
{
void *buffer = allocator_.allocate(size, alignment, __func__);
owned_buffers_.append(buffer);
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
owned_allocation_size_ += size;
#endif
return buffer;
}
};

View File

@ -285,7 +285,8 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
/** Validate the integrity of a given ListBase, returns `true` if evrything is OK, false otherwise.
/** Validate the integrity of a given ListBase, returns `true` if everything is OK, false
* otherwise.
*/
bool BLI_listbase_validate(struct ListBase *lb);

View File

@ -621,7 +621,7 @@ bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUS
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blender Spesific File Relative Paths
/** \name Blender Specific File Relative Paths
* \{ */
/**

View File

@ -531,6 +531,14 @@ template<typename T> class MutableSpan {
return size_;
}
/**
* Returns the number of bytes referenced by this Span.
*/
constexpr int64_t size_in_bytes() const
{
return sizeof(T) * size_;
}
/**
* Returns true if the size is zero.
*/

View File

@ -30,6 +30,7 @@
# endif
#endif
#include "BLI_function_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_lazy_threading.hh"
#include "BLI_utildefines.h"
@ -37,7 +38,7 @@
namespace blender::threading {
template<typename Range, typename Function>
void parallel_for_each(Range &&range, const Function &function)
inline void parallel_for_each(Range &&range, const Function &function)
{
#ifdef WITH_TBB
tbb::parallel_for_each(range, function);
@ -48,27 +49,45 @@ void parallel_for_each(Range &&range, const Function &function)
#endif
}
namespace detail {
void parallel_for_impl(IndexRange range,
int64_t grain_size,
FunctionRef<void(IndexRange)> function);
} // namespace detail
template<typename Function>
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
inline void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
{
if (range.size() == 0) {
if (range.is_empty()) {
return;
}
#ifdef WITH_TBB
/* Invoking tbb for small workloads has a large overhead. */
if (range.size() >= grain_size) {
lazy_threading::send_hint();
tbb::parallel_for(
tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
[&](const tbb::blocked_range<int64_t> &subrange) {
function(IndexRange(subrange.begin(), subrange.size()));
});
if (range.size() <= grain_size) {
function(range);
return;
}
#else
UNUSED_VARS(grain_size);
#endif
function(range);
detail::parallel_for_impl(range, grain_size, function);
}
/**
* Move the sub-range boundaries down to the next aligned index. The "global" begin and end
* remain fixed though.
*/
inline IndexRange align_sub_range(const IndexRange unaligned_range,
const int64_t alignment,
const IndexRange global_range)
{
const int64_t global_begin = global_range.start();
const int64_t global_end = global_range.one_after_last();
const int64_t alignment_mask = ~(alignment - 1);
const int64_t unaligned_begin = unaligned_range.start();
const int64_t unaligned_end = unaligned_range.one_after_last();
const int64_t aligned_begin = std::max(global_begin, unaligned_begin & alignment_mask);
const int64_t aligned_end = unaligned_end == global_end ?
unaligned_end :
std::max(global_begin, unaligned_end & alignment_mask);
const IndexRange aligned_range{aligned_begin, aligned_end - aligned_begin};
return aligned_range;
}
/**
@ -79,34 +98,23 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
* larger, which means that work is distributed less evenly.
*/
template<typename Function>
void parallel_for_aligned(const IndexRange range,
const int64_t grain_size,
const int64_t alignment,
const Function &function)
inline void parallel_for_aligned(const IndexRange range,
const int64_t grain_size,
const int64_t alignment,
const Function &function)
{
const int64_t global_begin = range.start();
const int64_t global_end = range.one_after_last();
const int64_t alignment_mask = ~(alignment - 1);
parallel_for(range, grain_size, [&](const IndexRange unaligned_range) {
/* Move the sub-range boundaries down to the next aligned index. The "global" begin and end
* remain fixed though. */
const int64_t unaligned_begin = unaligned_range.start();
const int64_t unaligned_end = unaligned_range.one_after_last();
const int64_t aligned_begin = std::max(global_begin, unaligned_begin & alignment_mask);
const int64_t aligned_end = unaligned_end == global_end ?
unaligned_end :
std::max(global_begin, unaligned_end & alignment_mask);
const IndexRange aligned_range{aligned_begin, aligned_end - aligned_begin};
const IndexRange aligned_range = align_sub_range(unaligned_range, alignment, range);
function(aligned_range);
});
}
template<typename Value, typename Function, typename Reduction>
Value parallel_reduce(IndexRange range,
int64_t grain_size,
const Value &identity,
const Function &function,
const Reduction &reduction)
inline Value parallel_reduce(IndexRange range,
int64_t grain_size,
const Value &identity,
const Function &function,
const Reduction &reduction)
{
#ifdef WITH_TBB
if (range.size() >= grain_size) {
@ -125,11 +133,30 @@ Value parallel_reduce(IndexRange range,
return function(range, identity);
}
template<typename Value, typename Function, typename Reduction>
inline Value parallel_reduce_aligned(const IndexRange range,
const int64_t grain_size,
const int64_t alignment,
const Value &identity,
const Function &function,
const Reduction &reduction)
{
parallel_reduce(
range,
grain_size,
identity,
[&](const IndexRange unaligned_range, const Value &ident) {
const IndexRange aligned_range = align_sub_range(unaligned_range, alignment, range);
function(aligned_range, ident);
},
reduction);
}
/**
* Execute all of the provided functions. The functions might be executed in parallel or in serial
* or some combination of both.
*/
template<typename... Functions> void parallel_invoke(Functions &&...functions)
template<typename... Functions> inline void parallel_invoke(Functions &&...functions)
{
#ifdef WITH_TBB
tbb::parallel_invoke(std::forward<Functions>(functions)...);
@ -144,7 +171,7 @@ template<typename... Functions> void parallel_invoke(Functions &&...functions)
* tasks.
*/
template<typename... Functions>
void parallel_invoke(const bool use_threading, Functions &&...functions)
inline void parallel_invoke(const bool use_threading, Functions &&...functions)
{
if (use_threading) {
lazy_threading::send_hint();
@ -156,7 +183,7 @@ void parallel_invoke(const bool use_threading, Functions &&...functions)
}
/** See #BLI_task_isolate for a description of what isolating a task means. */
template<typename Function> void isolate_task(const Function &function)
template<typename Function> inline void isolate_task(const Function &function)
{
#ifdef WITH_TBB
lazy_threading::ReceiverIsolation isolation;

View File

@ -403,7 +403,7 @@ int BLI_rename_overwrite(const char *from, const char *to)
* Support for checking the files aren't the same could be added, however path comparison
* alone is *not* a guarantee the files are different (given the possibility of accessing
* the same file through different paths via symbolic-links), we could instead support a
* verizon of Python's * `os.path.samefile(..)` which compares the I-node & device.
* version of Python's `os.path.samefile(..)` which compares the I-node & device.
* In this particular case we would not want to follow symbolic-links as well.
* Since this functionality isn't required at the moment, leave this as-is.
* Noting it as a potential improvement. */

View File

@ -352,7 +352,7 @@ void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
BLI_assert(!(q[0] < 0.0f));
/* Sometimes normalisation is necessary due to round-off errors in the above
/* Sometimes normalization is necessary due to round-off errors in the above
* calculations. The comparison here uses tighter tolerances than
* BLI_ASSERT_UNIT_QUAT(), so it's likely that even after a few more
* transformations the quaternion will still be considered unit-ish. */

View File

@ -344,7 +344,7 @@ void BLI_str_cursor_step_bounds_utf8(
BLI_str_cursor_step_utf8(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
}
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
/* Expand forward if we are between similar content. */
BLI_str_cursor_step_utf8(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
}
}
@ -361,11 +361,11 @@ void BLI_str_cursor_step_bounds_utf32(
*r_end = pos;
if ((prev <= next) && (prev != STRCUR_DELIM_NONE)) {
/* Expand backward if we are between similar content, before whitespace, or at end. */
/* Expand backward if we are between similar content. */
BLI_str_cursor_step_utf32(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
}
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
/* Expand forward if we are between similar content. */
BLI_str_cursor_step_utf32(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
}
}

View File

@ -14,6 +14,7 @@
#include "BLI_lazy_threading.hh"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_threads.h"
#include "atomic_ops.h"
@ -154,3 +155,28 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS * /*tls*/)
return 0;
#endif
}
namespace blender::threading::detail {
void parallel_for_impl(const IndexRange range,
const int64_t grain_size,
const FunctionRef<void(IndexRange)> function)
{
#ifdef WITH_TBB
/* Invoking tbb for small workloads has a large overhead. */
if (range.size() >= grain_size) {
lazy_threading::send_hint();
tbb::parallel_for(
tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
[function](const tbb::blocked_range<int64_t> &subrange) {
function(IndexRange(subrange.begin(), subrange.size()));
});
return;
}
#else
UNUSED_VARS(grain_size);
#endif
function(range);
}
} // namespace blender::threading::detail

View File

@ -130,4 +130,23 @@ TEST(function_ref, InitializeWithNull)
EXPECT_FALSE(f);
}
static int overload_test(const FunctionRef<void(std::string)> /*fn*/)
{
return 1;
}
static int overload_test(const FunctionRef<void(int)> /*fn*/)
{
return 2;
}
TEST(function_ref, OverloadSelection)
{
const auto fn_1 = [](std::string /*x*/) {};
const auto fn_2 = [](int /*x*/) {};
EXPECT_EQ(overload_test(fn_1), 1);
EXPECT_EQ(overload_test(fn_2), 2);
}
} // namespace blender::tests

View File

@ -149,4 +149,23 @@ TEST(linear_allocator, ConstructArray)
}
}
TEST(linear_allocator, TransferOwnership)
{
LinearAllocator<> main_allocator;
MutableSpan<int> values;
/* Allocate a large buffer that is likely to be given back to the system when freed. This test
* essentially only fails by crashing with a segfault. */
const int size = 1'000'000;
const int value = 42;
const int index = 500'000;
{
LinearAllocator<> nested_allocator;
values = nested_allocator.allocate_array<int>(size);
values[index] = value;
main_allocator.transfer_ownership_from(nested_allocator);
}
EXPECT_EQ(values[index], value);
}
} // namespace blender::tests

View File

@ -271,12 +271,15 @@ struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
* However, now only pointers to ID data blocks are updated.
* \{ */
/** Search for the new address of given `id`, during liblinking part of blendfile reading process.
/**
* Search for the new address of given `id`,
* during library linking part of blend-file reading process.
*
* \param self_id the ID owner of the given `id` pointer. Note that it may be an embedded ID.
* \param do_linked_only If `true`, only return found pointer if it is a linked ID. Used to
* preventlinked data to point to local IDs.
* \return the new address of the given ID pointer, or null if not found. */
* \param self_id: the ID owner of the given `id` pointer. Note that it may be an embedded ID.
* \param do_linked_only: If `true`, only return found pointer if it is a linked ID. Used to
* prevent linked data to point to local IDs.
* \return the new address of the given ID pointer, or null if not found.
*/
ID *BLO_read_get_new_id_address(BlendLibReader *reader,
struct ID *self_id,
const bool do_linked_only,

View File

@ -199,7 +199,7 @@ bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
shapekey->from);
/* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
* `G_MAIN`, default UI-handling remapping callback (defined by call to
* `BKE_library_callback_remap_editor_id_reference_set`) won't work on exoected data here. */
* `BKE_library_callback_remap_editor_id_reference_set`) won't work on expected data here. */
BKE_id_delete_ex(bmain, shapekey, ID_REMAP_FORCE_UI_POINTERS);
}

View File

@ -98,7 +98,7 @@ typedef struct FileData {
/**
* Store mapping from old ID pointers (the values they have in the .blend file) to new ones,
* typically from value in `bhead->old` to address in memory where the ID was read.
* Used during liblinking process (see #lib_link_all).
* Used during library-linking process (see #lib_link_all).
*/
struct OldNewMap *libmap;
@ -115,7 +115,7 @@ typedef struct FileData {
/** Used for undo. */
ListBase *old_mainlist;
/**
* IDMap using uuids as keys of all the old IDs in the old bmain. Used during undo to find a
* IDMap using UUID's as keys of all the old IDs in the old bmain. Used during undo to find a
* matching old data when reading a new ID. */
struct IDNameLib_Map *old_idmap_uuid;

View File

@ -996,8 +996,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
* to the evaluated #Mesh, so here we ensure that the basis
* shape key is always set in the mesh coordinates. */
for (me = bmain->meshes.first; me; me = me->id.next) {
if ((key = blo_do_versions_newlibadr(fd, &me->id, ID_IS_LINKED(me), me->key)) &&
key->refkey) {
if ((key = blo_do_versions_newlibadr(fd, &me->id, ID_IS_LINKED(me), me->key)) && key->refkey)
{
data = key->refkey->data;
tot = MIN2(me->totvert, key->refkey->totelem);
MVert *verts = (MVert *)CustomData_get_layer_for_write(&me->vdata, CD_MVERT, me->totvert);
@ -1008,8 +1008,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (lt = bmain->lattices.first; lt; lt = lt->id.next) {
if ((key = blo_do_versions_newlibadr(fd, &lt->id, ID_IS_LINKED(lt), lt->key)) &&
key->refkey) {
if ((key = blo_do_versions_newlibadr(fd, &lt->id, ID_IS_LINKED(lt), lt->key)) && key->refkey)
{
data = key->refkey->data;
tot = MIN2(lt->pntsu * lt->pntsv * lt->pntsw, key->refkey->totelem);
@ -1020,8 +1020,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
if ((key = blo_do_versions_newlibadr(fd, &cu->id, ID_IS_LINKED(cu), cu->key)) &&
key->refkey) {
if ((key = blo_do_versions_newlibadr(fd, &cu->id, ID_IS_LINKED(cu), cu->key)) && key->refkey)
{
data = key->refkey->data;
for (nu = cu->nurb.first; nu; nu = nu->next) {

View File

@ -644,6 +644,11 @@ static bool seq_speed_factor_set(Sequence *seq, void *user_data)
seq_speed_factor_fix_rna_path(seq, &scene->adt->drivers);
}
/* Pitch value of 0 has been found in some files. This would cause problems. */
if (seq->pitch <= 0.0f) {
seq->pitch = 1.0f;
}
seq->speed_factor = seq->pitch;
}
else {
@ -2317,6 +2322,73 @@ static void version_ensure_missing_regions(ScrArea *area, SpaceLink *sl)
}
}
/**
* Change override RNA path from `frame_{start,end}` to `frame_{start,end}_raw`.
* See #102662.
*/
static void version_liboverride_nla_strip_frame_start_end(IDOverrideLibrary *liboverride,
const char *parent_rna_path,
NlaStrip *strip)
{
if (!strip) {
return;
}
/* Escape the strip name for inclusion in the RNA path. */
char name_esc_strip[sizeof(strip->name) * 2];
BLI_str_escape(name_esc_strip, strip->name, sizeof(name_esc_strip));
const std::string rna_path_strip = std::string(parent_rna_path) + ".strips[\"" + name_esc_strip +
"\"]";
{ /* Rename .frame_start -> .frame_start_raw: */
const std::string rna_path_prop = rna_path_strip + ".frame_start";
BKE_lib_override_library_property_rna_path_change(
liboverride, rna_path_prop.c_str(), (rna_path_prop + "_raw").c_str());
}
{ /* Rename .frame_end -> .frame_end_raw: */
const std::string rna_path_prop = rna_path_strip + ".frame_end";
BKE_lib_override_library_property_rna_path_change(
liboverride, rna_path_prop.c_str(), (rna_path_prop + "_raw").c_str());
}
{ /* Remove .frame_start_ui: */
const std::string rna_path_prop = rna_path_strip + ".frame_start_ui";
BKE_lib_override_library_property_search_and_delete(liboverride, rna_path_prop.c_str());
}
{ /* Remove .frame_end_ui: */
const std::string rna_path_prop = rna_path_strip + ".frame_end_ui";
BKE_lib_override_library_property_search_and_delete(liboverride, rna_path_prop.c_str());
}
/* Handle meta-strip contents. */
LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
version_liboverride_nla_strip_frame_start_end(liboverride, rna_path_strip.c_str(), substrip);
}
}
/** Fix the `frame_start` and `frame_end` overrides on NLA strips. See #102662. */
static void version_liboverride_nla_frame_start_end(ID *id, AnimData *adt, void * /*user_data*/)
{
IDOverrideLibrary *liboverride = id->override_library;
if (!liboverride) {
return;
}
int track_index;
LISTBASE_FOREACH_INDEX (NlaTrack *, track, &adt->nla_tracks, track_index) {
char *rna_path_track = BLI_sprintfN("animation_data.nla_tracks[%d]", track_index);
LISTBASE_FOREACH (NlaStrip *, strip, &track->strips) {
version_liboverride_nla_strip_frame_start_end(liboverride, rna_path_track, strip);
}
MEM_freeN(rna_path_track);
}
}
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
{
@ -3251,20 +3323,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type != NTREE_GEOMETRY) {
continue;
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type != GEO_NODE_REALIZE_INSTANCES) {
continue;
}
node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 301, 6)) {
/* Add node storage for map range node. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
@ -4418,5 +4476,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
versioning_remove_microfacet_sharp_distribution(ntree);
}
FOREACH_NODETREE_END;
BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end, NULL);
}
}

View File

@ -234,7 +234,7 @@ void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
slot_dst->data.buf = NULL;
slot_dst->len = slot_src->len;
if (slot_dst->len) {
/* check dest has all flags enabled that the source has */
/* Check destination has all flags enabled that the source has. */
const eBMOpSlotSubType_Elem src_elem_flag = (slot_src->slot_subtype.elem & BM_ALL_NOLOOP);
const eBMOpSlotSubType_Elem dst_elem_flag = (slot_dst->slot_subtype.elem & BM_ALL_NOLOOP);

View File

@ -293,7 +293,7 @@ void DeferredLayer::begin_sync()
/* Textures. */
prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
/* Uniform Buf. */
/* Uniform Buffer. */
prepass_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
inst_.velocity.bind_resources(&prepass_ps_);
@ -338,11 +338,11 @@ void DeferredLayer::begin_sync()
gbuffer_ps_.bind_image(RBUFS_AOV_VALUE_SLOT, &inst_.render_buffers.aov_value_tx);
/* Cryptomatte. */
gbuffer_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx);
/* Storage Buf. */
/* Storage Buffer. */
gbuffer_ps_.bind_ssbo(RBUFS_AOV_BUF_SLOT, &inst_.film.aovs_info);
/* Textures. */
gbuffer_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
/* Uniform Buf. */
/* Uniform Buffer. */
gbuffer_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
inst_.sampling.bind_resources(&gbuffer_ps_);

View File

@ -89,7 +89,7 @@ class Sampling {
template<typename T> void bind_resources(draw::detail::PassBase<T> *pass)
{
/* Storage Buf. */
/* Storage Buffer. */
pass->bind_ssbo(SAMPLING_BUF_SLOT, &data_);
}

View File

@ -120,13 +120,13 @@ class VelocityModule {
template<typename T> void bind_resources(draw::detail::Pass<T> *pass)
{
/* Storage Buf. */
/* Storage Buffer. */
pass->bind_ssbo(VELOCITY_OBJ_PREV_BUF_SLOT, &(*object_steps[STEP_PREVIOUS]));
pass->bind_ssbo(VELOCITY_OBJ_NEXT_BUF_SLOT, &(*object_steps[next_step_]));
pass->bind_ssbo(VELOCITY_GEO_PREV_BUF_SLOT, &(*geometry_steps[STEP_PREVIOUS]));
pass->bind_ssbo(VELOCITY_GEO_NEXT_BUF_SLOT, &(*geometry_steps[next_step_]));
pass->bind_ssbo(VELOCITY_INDIRECTION_BUF_SLOT, &indirection_buf);
/* Uniform Buf. */
/* Uniform Buffer. */
pass->bind_ubo(VELOCITY_CAMERA_PREV_BUF, &(*camera_steps[STEP_PREVIOUS]));
pass->bind_ubo(VELOCITY_CAMERA_CURR_BUF, &(*camera_steps[STEP_CURRENT]));
pass->bind_ubo(VELOCITY_CAMERA_NEXT_BUF, &(*camera_steps[next_step_]));

View File

@ -61,7 +61,6 @@ static int g_tf_target_width;
static int g_tf_target_height;
static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>;
@ -121,8 +120,6 @@ void DRW_curves_init(DRWData *drw_data)
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
/* Create vbo immediately to bind to texture buffer. */
GPU_vertbuf_use(g_dummy_vbo);
g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
}
}
@ -318,12 +315,12 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
/* Fix issue with certain driver not drawing anything if there is no texture bound to
/* Fix issue with certain driver not drawing anything if there is nothing bound to
* "ac", "au", "u" or "c". */
DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo);
DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo);
DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo);
DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo);
/* TODO: Generalize radius implementation for curves data type. */
float hair_rad_shape = 0.0f;
@ -415,7 +412,7 @@ void DRW_curves_update()
/* Update legacy hair too, to avoid verbosity in callers. */
DRW_hair_update();
if (!GPU_transform_feedback_support()) {
if (drw_curves_shader_type_get() == PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND) {
/**
* Workaround to transform feedback not working on mac.
* On some system it crashes (see #58489) and on some other it renders garbage (see #60171).
@ -538,5 +535,4 @@ void DRW_curves_free()
DRW_hair_free();
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
}

View File

@ -64,7 +64,6 @@ static int g_tf_target_width;
static int g_tf_target_height;
static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple #DRWManager in the future */
static blender::draw::UniformBuffer<CurvesInfos> *g_dummy_curves_info = nullptr;
@ -96,8 +95,6 @@ void DRW_hair_init(void)
/* Create VBO immediately to bind to texture buffer. */
GPU_vertbuf_use(g_dummy_vbo);
g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>(
"g_dummy_curves_info");
memset(g_dummy_curves_info->is_point_attribute,
@ -266,15 +263,15 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
}
}
/* Fix issue with certain driver not drawing anything if there is no texture bound to
/* Fix issue with certain driver not drawing anything if there is nothing bound to
* "ac", "au", "u" or "c". */
if (hair_cache->num_uv_layers == 0) {
DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo);
DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo);
}
if (hair_cache->num_col_layers == 0) {
DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo);
DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo);
}
DRW_hair_duplimat_get(object, psys, md, dupli_mat);
@ -314,7 +311,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
void DRW_hair_update()
{
if (!GPU_transform_feedback_support()) {
if (drw_hair_shader_type_get() == PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND) {
/**
* Workaround to transform feedback not working on mac.
* On some system it crashes (see #58489) and on some other it renders garbage (see #60171).
@ -433,6 +430,5 @@ void DRW_hair_update()
void DRW_hair_free(void)
{
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
MEM_delete(g_dummy_curves_info);
}

View File

@ -2792,6 +2792,9 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
/* Only background (non-edit) objects are used for occlusion. */
continue;
}
if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
}
drw_engines_cache_populate(ob);
}
DEG_OBJECT_ITER_END;

View File

@ -203,16 +203,13 @@ static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event, Sp
}
}
static void change_frame_seq_preview_end(bContext *C, SpaceSeq *sseq)
static void change_frame_seq_preview_end(SpaceSeq *sseq)
{
BLI_assert(sseq != NULL);
UNUSED_VARS_NDEBUG(sseq);
if (ED_sequencer_special_preview_get() != NULL) {
ED_sequencer_special_preview_clear();
}
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
static bool use_sequencer_snapping(bContext *C)
@ -260,6 +257,36 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
return OPERATOR_RUNNING_MODAL;
}
static bool need_extra_redraw_after_scrubbing_ends(bContext *C)
{
if (CTX_wm_space_seq(C)) {
/* During scrubbing in the sequencer, a preview of the final video might be drawn. After
* scrubbing, the actual result should be shown again. */
return true;
}
wmWindowManager *wm = CTX_wm_manager(C);
Object *object = CTX_data_active_object(C);
if (object && object->type == OB_GPENCIL_LEGACY) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) {
/* Grease pencil onion skin is not drawn during scrubbing. Redraw is necessary after
* scrubbing ends to show onion skin again. */
return true;
}
}
}
}
}
}
return false;
}
static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
{
bScreen *screen = CTX_wm_screen(C);
@ -267,7 +294,12 @@ static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq != NULL) {
change_frame_seq_preview_end(C, sseq);
change_frame_seq_preview_end(sseq);
}
if (need_extra_redraw_after_scrubbing_ends(C)) {
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
}
@ -323,7 +355,11 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq != NULL) {
change_frame_seq_preview_end(C, sseq);
change_frame_seq_preview_end(sseq);
}
if (need_extra_redraw_after_scrubbing_ends(C)) {
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
}

View File

@ -397,8 +397,8 @@ static void generator_panel_draw(const bContext *C, Panel *panel)
uiLayoutColumn(split, false);
uiLayout *title_col = uiLayoutColumn(split, false);
uiLayout *title_row = uiLayoutRow(title_col, true);
uiItemL(title_row, IFACE_("A"), ICON_NONE);
uiItemL(title_row, IFACE_("B"), ICON_NONE);
uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "A"), ICON_NONE);
uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "B"), ICON_NONE);
}
uiLayout *first_row = uiLayoutRow(col, true);

View File

@ -1142,7 +1142,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
* A symmetrizable selection contains selected ebones of the input direction
* and unique selected bones with an unique flippable name.
*
* Storing temp ptrs to mirrored unselected ebones. */
* Storing temp pointers to mirrored unselected ebones. */
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) {
/* Skipping invisible selected bones. */

View File

@ -419,8 +419,9 @@ void paintface_select_linked(struct bContext *C,
struct Object *ob,
const int mval[2],
bool select);
/** Grow the selection of faces.
* \param face_step If true will also select faces that only touch on the corner.
/**
* Grow the selection of faces.
* \param face_step: If true will also select faces that only touch on the corner.
*/
void paintface_select_more(struct Mesh *mesh, bool face_step);
void paintface_select_less(struct Mesh *mesh, bool face_step);

View File

@ -125,8 +125,9 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_CURSOR_EDIT (1 << 16)
#define P_CLNOR_INVALIDATE (1 << 17)
#define P_VIEW2D_EDGE_PAN (1 << 18)
#define P_VIEW3D_NAVIGATION (1 << 19)
/* For properties performed when confirming the transformation. */
#define P_POST_TRANSFORM (1 << 19)
#define P_POST_TRANSFORM (1 << 20)
void Transform_Properties(struct wmOperatorType *ot, int flags);

View File

@ -43,6 +43,7 @@ struct SnapObjectContext;
struct View3D;
struct ViewContext;
struct ViewLayer;
struct ViewOpsData;
struct bContext;
struct bPoseChannel;
struct bScreen;
@ -210,6 +211,19 @@ bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
double depth,
float r_location_world[3]);
/**
* Utilities to perform navigation.
* Call `ED_view3d_navigation_init` to create a context and `ED_view3d_navigation_do` to perform
* navigation in modal operators.
*
* \note modal map events can also be used in `ED_view3d_navigation_do`.
*/
struct ViewOpsData *ED_view3d_navigation_init(struct bContext *C);
bool ED_view3d_navigation_do(struct bContext *C,
struct ViewOpsData *vod,
const struct wmEvent *event);
void ED_view3d_navigation_free(struct bContext *C, struct ViewOpsData *vod);
/* Projection */
#define IS_CLIPPED 12000

View File

@ -191,11 +191,11 @@ static void ui_popup_menu_create_block(bContext *C,
if (!pup->but) {
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
/* A title is only provided when a Menu has a label, this is not alwas the case, see e.g.
/* A title is only provided when a Menu has a label, this is not always the case, see e.g.
* `VIEW3D_MT_edit_mesh_context_menu` -- this specifies its own label inside the draw function
* depending on vertex/edge/face mode. We still want to flag the uiBlock (but only insert into
* the puphash if we have a title provided). Choosing an entry in a menu will still handle
* puphash later (see `button_activate_exit`) though multiple menus without a label might fight
* the `puphash` if we have a title provided). Choosing an entry in a menu will still handle
* `puphash` later (see `button_activate_exit`) though multiple menus without a label might fight
* for the same storage of the menu memory. Using idname instead (or in combination with the
* label) for the hash could be looked at to solve this. */
pup->block->flag |= UI_BLOCK_POPUP_MEMORY;

View File

@ -71,8 +71,8 @@ static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt)
memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len_src);
}
/* Even for the same amount of points we dont just copy memory for MDeformVert, relations to
* MDeformWeight might have changed. */
/* Even for the same amount of points we don't just copy memory for MDeformVert,
* relations to #MDeformWeight might have changed. */
if (editlatt->latt->dvert && ult->dvert) {
BKE_defvert_array_free(editlatt->latt->dvert, len_dst);
editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * len_src, "Lattice MDeformVert");

View File

@ -2796,7 +2796,7 @@ static int vertex_group_copy_exec(bContext *C, wmOperator * /*op*/)
void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Copy Vertex Group";
ot->name = "Duplicate Vertex Group";
ot->idname = "OBJECT_OT_vertex_group_copy";
ot->description = "Make a copy of the active vertex group";

View File

@ -4508,6 +4508,11 @@ static bool match_region_with_redraws(const ScrArea *area,
return true;
}
break;
case SPACE_SPREADSHEET:
if ((redraws & TIME_SPREADSHEETS)) {
return true;
}
break;
default:
break;
}

View File

@ -1934,7 +1934,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
zero_v4(projPixel->newColor.f);
}
else {
projPixel->pixel.ch_pt = ibuf->byte_buffer.data + (x_px + y_px * ibuf->x);
projPixel->pixel.ch_pt = ibuf->byte_buffer.data + (x_px + y_px * ibuf->x) * 4;
projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
projPixel->newColor.uint_ = 0;
}

View File

@ -235,8 +235,8 @@ static void imapaint_tri_weights(float matrix[4][4],
h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
h[2] = 1.0f;
/* solve for (w1,w2,w3)/perspdiv in:
* h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
/* Solve for `(w1,w2,w3)/perspdiv` in:
* `h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3)`. */
wmat[0][0] = pv1[0];
wmat[1][0] = pv2[0];
@ -253,7 +253,7 @@ static void imapaint_tri_weights(float matrix[4][4],
copy_v3_v3(w, h);
/* w is still divided by perspdiv, make it sum to one */
/* w is still divided by `perspdiv`, make it sum to one */
divw = w[0] + w[1] + w[2];
if (divw != 0.0f) {
mul_v3_fl(w, 1.0f / divw);

View File

@ -58,7 +58,7 @@ bool ED_wpaint_ensure_data(bContext *C,
return false;
}
/* if nothing was added yet, we make dverts and a vertex deform group */
/* If nothing was added yet, we make deform-verts and a vertex deform group. */
if (BKE_mesh_deform_verts(me) == nullptr) {
BKE_object_defgroup_data_create(&me->id);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
@ -136,8 +136,7 @@ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
}
}
/* curdef should never be nullptr unless this is
* a light and BKE_object_defgroup_add_name fails */
/* `mirrdef` shouldn't be -1 unless the object is a light & #BKE_object_defgroup_new fails. */
return mirrdef;
}

View File

@ -445,9 +445,9 @@ static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
const View2D *v2d = UI_view2d_fromcontext(C);
/* TODO: This is hardcoded behavior, same as preselect gizmos in 3D view.
/* TODO: This is hard-coded behavior, same as pre-select gizmos in 3D view.
* Better solution would be to check operator keymap and display this information in status bar
* and tooltip. */
* and tool-tip. */
wmEvent *event = CTX_wm_window(C)->eventstate;
gizmo->create_transition_operation = (event->modifier & KM_SHIFT) != 0;

View File

@ -216,7 +216,7 @@ static int sequencer_retiming_handle_move_modal(bContext *C, wmOperator *op, con
const bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
const bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
/* When working with transiton, change handles when moving past pivot point. */
/* When working with transition, change handles when moving past pivot point. */
if (handle_is_transition || prev_handle_is_transition) {
SeqRetimingHandle *transition_start, *transition_end;
if (handle_is_transition) {

View File

@ -74,6 +74,8 @@ const char *viewops_operator_idname_get(eV3D_OpMode nav_type)
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
return "VIEW3D_OT_ndof_orbit_zoom";
#endif
case V3D_OP_MODE_NONE:
break;
}
BLI_assert(false);
return nullptr;
@ -1942,3 +1944,142 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Navigation Utilities
* \{ */
/* Detect the navigation operation, by the name of the navigation operator (obtained by
* `wmKeyMapItem::idname`) */
static eV3D_OpMode view3d_navigation_type_from_idname(const char *idname)
{
const char *op_name = idname + sizeof("VIEW3D_OT_");
for (int i = 0; i < V3D_OP_MODE_LEN; i++) {
if (STREQ(op_name, viewops_operator_idname_get((eV3D_OpMode)i) + sizeof("VIEW3D_OT_"))) {
return (eV3D_OpMode)i;
}
}
return V3D_OP_MODE_NONE;
}
/* Unlike `viewops_data_create`, `ED_view3d_navigation_init` creates a navigation context along
* with an array of `wmKeyMapItem`s used for navigation. */
ViewOpsData *ED_view3d_navigation_init(bContext *C)
{
if (!CTX_wm_region_view3d(C)) {
return NULL;
}
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
viewops_data_init_context(C, vod);
vod->keymap = WM_keymap_find_all(CTX_wm_manager(C), "3D View", SPACE_VIEW3D, 0);
return vod;
}
/* Checks and initializes the navigation modal operation. */
static int view3d_navigation_invoke(bContext *C,
ViewOpsData *vod,
const wmEvent *event,
struct wmKeyMapItem *kmi,
eV3D_OpMode nav_type)
{
switch (nav_type) {
case V3D_OP_MODE_ZOOM:
if (!view3d_zoom_or_dolly_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_MOVE:
case V3D_OP_MODE_VIEW_PAN:
if (!view3d_location_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_ROTATE:
if (!view3d_rotation_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_VIEW_ROLL:
case V3D_OP_MODE_DOLLY:
#ifdef WITH_INPUT_NDOF
case V3D_OP_MODE_NDOF_ORBIT:
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
#endif
case V3D_OP_MODE_NONE:
break;
}
return view3d_navigation_invoke_generic(C, vod, event, kmi->ptr, nav_type);
}
bool ED_view3d_navigation_do(bContext *C, ViewOpsData *vod, const wmEvent *event)
{
if (!vod) {
return false;
}
wmEvent event_tmp;
if (event->type == EVT_MODAL_MAP) {
/* Workaround to use the original event values. */
event_tmp = *event;
event_tmp.type = event->prev_type;
event_tmp.val = event->prev_val;
event = &event_tmp;
}
int op_return = OPERATOR_CANCELLED;
if (vod->is_modal_event) {
const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
op_return = view3d_navigation_modal(C, vod, event_code, event->xy);
if (op_return != OPERATOR_RUNNING_MODAL) {
viewops_data_end_navigation(C, vod);
vod->is_modal_event = false;
}
}
else {
eV3D_OpMode nav_type;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &vod->keymap->items) {
if (!STRPREFIX(kmi->idname, "VIEW3D")) {
continue;
}
if (kmi->flag & KMI_INACTIVE) {
continue;
}
if ((nav_type = view3d_navigation_type_from_idname(kmi->idname)) == V3D_OP_MODE_NONE) {
continue;
}
if (!WM_event_match(event, kmi)) {
continue;
}
op_return = view3d_navigation_invoke(C, vod, event, kmi, nav_type);
if (op_return == OPERATOR_RUNNING_MODAL) {
vod->is_modal_event = true;
}
else {
viewops_data_end_navigation(C, vod);
}
break;
}
}
if (op_return != OPERATOR_CANCELLED) {
/* Although #ED_view3d_update_viewmat is already called when redrawing the 3D View, do it here
* as well, so the updated matrix values can be accessed by the operator. */
ED_view3d_update_viewmat(
vod->depsgraph, vod->scene, vod->v3d, vod->region, NULL, NULL, NULL, false);
return true;
}
return false;
}
void ED_view3d_navigation_free(bContext *C, ViewOpsData *vod)
{
viewops_data_free(C, vod);
}
/** \} */

View File

@ -33,6 +33,7 @@ struct wmEvent;
struct wmOperator;
typedef enum eV3D_OpMode {
V3D_OP_MODE_NONE = -1,
V3D_OP_MODE_ZOOM = 0,
V3D_OP_MODE_ROTATE,
V3D_OP_MODE_MOVE,
@ -44,6 +45,11 @@ typedef enum eV3D_OpMode {
V3D_OP_MODE_NDOF_ORBIT_ZOOM,
#endif
} eV3D_OpMode;
#ifndef WITH_INPUT_NDOF
# define V3D_OP_MODE_LEN V3D_OP_MODE_DOLLY + 1
#else
# define V3D_OP_MODE_LEN V3D_OP_MODE_NDOF_ORBIT_ZOOM + 1
#endif
enum eV3D_OpPropFlag {
V3D_OP_PROP_MOUSE_CO = (1 << 0),
@ -179,6 +185,10 @@ typedef struct ViewOpsData {
* See #view3d_orbit_apply_dyn_ofs code-comments for an example, also see: #104385.
*/
bool use_dyn_ofs_ortho_correction;
/** Used for navigation on non view3d operators. */
wmKeyMap *keymap;
bool is_modal_event;
} ViewOpsData;
/* view3d_navigate.cc */

View File

@ -891,7 +891,7 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
mul_qt_v3(viewinv, view_dst_x);
mul_qt_v3(viewinv, view_dst_y);
/* check source and dest have a matching axis */
/* Check source and destination have a matching axis. */
for (i = 0; i < 3; i++) {
if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))

View File

@ -92,9 +92,6 @@ void setTransformViewMatrices(TransInfo *t)
unit_m4(t->persinv);
t->persp = RV3D_ORTHO;
}
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
}
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@ -926,15 +923,17 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
int transformEvent(TransInfo *t, const wmEvent *event)
{
bool handled = false;
bool is_navigating = t->vod ? ((RegionView3D *)t->region->regiondata)->rflag & RV3D_NAVIGATING :
false;
/* Handle modal numinput events first, if already activated. */
if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) && hasNumInput(&t->num) &&
handleNumInput(t->context, &(t->num), event))
if (!is_navigating && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
{
t->redraw |= TREDRAW_HARD;
handled = true;
}
else if (event->type == MOUSEMOVE) {
else if (!is_navigating && event->type == MOUSEMOVE) {
copy_v2_v2_int(t->mval, event->mval);
/* Use this for soft redraw. Might cause flicker in object mode */

View File

@ -41,6 +41,7 @@ struct TransDataContainer;
struct TransInfo;
struct TransSnap;
struct ViewLayer;
struct ViewOpsData;
struct bContext;
struct wmEvent;
struct wmKeyConfig;
@ -673,6 +674,8 @@ typedef struct TransInfo {
/** Currently only used for random curve of proportional editing. */
struct RNG *rng;
struct ViewOpsData *vod;
/** Typically for mode settings. */
TransCustomDataContainer custom;

View File

@ -660,7 +660,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag |= T_NO_CURSOR_WRAP;
}
if (op && (t->flag & T_MODAL) && !(t->flag & T_RELEASE_CONFIRM) &&
(prop = RNA_struct_find_property(op->ptr, "allow_navigation")) &&
RNA_property_boolean_get(op->ptr, prop))
{
t->vod = ED_view3d_navigation_init(C);
}
setTransformViewMatrices(t);
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
initNumInput(&t->num);
transform_gizmo_3d_model_from_constraint_and_mode_init(t);
@ -770,6 +779,10 @@ void postTrans(bContext *C, TransInfo *t)
}
freeSnapping(t);
if (t->vod) {
ED_view3d_navigation_free(C, t->vod);
}
}
void applyTransObjects(TransInfo *t)

View File

@ -474,6 +474,23 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
}
/* Similar to #transform_object_deform_pose_armature_get but does not check visibility. */
static Object *gizmo_3d_transform_space_object_get(Scene *scene, ViewLayer *view_layer)
{
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
/* It is assumed that when the object is in Weight Paint mode, it is not in Edit mode. So we
* don't need to check the #OB_MODE_EDIT flag. */
BLI_assert(!(ob->mode & OB_MODE_EDIT));
Object *obpose = BKE_object_pose_armature_get(ob);
if (obpose != nullptr) {
ob = obpose;
}
}
return ob;
}
/**
* Run \a user_fn for each coordinate of elements selected in View3D (vertices, particles...).
* \note Each coordinate has the space matrix of the active object.
@ -519,15 +536,7 @@ static int gizmo_3d_foreach_selected(const bContext *C,
const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
int a, totsel = 0;
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
Object *obpose = BKE_object_pose_armature_get(ob);
if (obpose != nullptr) {
ob = obpose;
}
}
Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
if (is_gp_edit) {
float diff_mat[4][4];
@ -586,7 +595,7 @@ static int gizmo_3d_foreach_selected(const bContext *C,
}
}
}
else if (obedit) {
else if (Object *obedit = OBEDIT_FROM_OBACT(ob)) {
#define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \
{ \
@ -937,15 +946,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
(params->orientation_index - 1) :
BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
Object *obpose = BKE_object_pose_armature_get(ob);
if (obpose != nullptr) {
ob = obpose;
}
}
tbounds->use_matrix_space = false;
unit_m3(tbounds->axis);
@ -972,7 +974,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
copy_m3_m4(diff_mat, ob->object_to_world);
normalize_m3(diff_mat);
invert_m3(diff_mat);
mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
mul_m3_m3_pre(tbounds->axis, diff_mat);
normalize_m3(tbounds->axis);
tbounds->use_matrix_space = true;
@ -997,7 +999,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
if (!is_gp_edit && (obedit || (ob && (ob->mode & (OB_MODE_POSE | OB_MODE_SCULPT))))) {
if (ob && (ob->mode & OB_MODE_POSE)) {
if (ob->mode & OB_MODE_POSE) {
invert_m4_m4(ob->world_to_object, ob->object_to_world);
}
mul_m4_v3(ob->object_to_world, tbounds->center);

View File

@ -399,7 +399,7 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
int exit_code;
int exit_code = OPERATOR_PASS_THROUGH;
TransInfo *t = op->customdata;
const eTfmMode mode_prev = t->mode;
@ -419,6 +419,31 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
exit_code = transformEvent(t, event);
t->context = NULL;
/* Allow navigation while transforming. */
if (t->vod && (exit_code & OPERATOR_PASS_THROUGH) && ED_view3d_navigation_do(C, t->vod, event)) {
RegionView3D *rv3d = t->region->regiondata;
if (rv3d->rflag & RV3D_NAVIGATING) {
/* Do not update transform while navigating. This can be distracting. */
return OPERATOR_RUNNING_MODAL;
}
if (t->modifiers & MOD_PRECISION) {
/* Remove Precision modifier, it may have be unintentionally enabled. */
t->modifiers &= ~MOD_PRECISION;
t->mouse.precision = 0;
}
/* Make sure `t->mval` is up to date before calling #transformViewUpdate. */
copy_v2_v2_int(t->mval, event->mval);
/* Call before #applyMouseInput. */
tranformViewUpdate(t);
/* Mouse input is outdated. */
applyMouseInput(t, &t->mouse, t->mval, t->values);
t->redraw |= TREDRAW_HARD;
}
transformApply(C, t);
exit_code |= transformEnd(C, t);
@ -752,6 +777,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
if (flags & P_VIEW3D_NAVIGATION) {
prop = RNA_def_boolean(ot->srna,
"allow_navigation",
0,
"Allow Navigation",
"Allow navigation while transforming");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
if (flags & P_POST_TRANSFORM) {
prop = RNA_def_boolean(ot->srna,
"use_automerge_and_split",
@ -786,7 +820,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_VIEW2D_EDGE_PAN |
P_POST_TRANSFORM);
P_VIEW3D_NAVIGATION | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@ -825,7 +859,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP |
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
@ -902,7 +936,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
@ -1147,7 +1181,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
@ -1182,7 +1216,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
@ -1330,7 +1364,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static int transform_from_gizmo_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)

View File

@ -715,6 +715,10 @@ static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t)
/* Exclude editmesh when using proportional edit */
ret |= SCE_SNAP_TARGET_NOT_EDITED;
}
/* UV editing must never snap to the selection as this is what is transformed. */
if (t->spacetype == SPACE_IMAGE) {
ret |= SCE_SNAP_TARGET_NOT_SELECTED;
}
}
else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
/* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */

View File

@ -1150,12 +1150,12 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
return false; /* Nothing to do. */
}
/* Transform phis. */
/* Transform phis, rotate by best_angle, then translate back to the origin. No scale. */
for (const int64_t j : island_indices.index_range()) {
const int64_t i = island_indices[j]->index;
const PackIsland *island = islands[i];
const float island_scale = island->can_scale_(params) ? scale : 1.0f;
island->build_transformation(island_scale, square_finder.best_angle, matrix);
const float identity_scale = 1.0f; /* Don't rescale the placement, just rotate. */
island->build_transformation(identity_scale, square_finder.best_angle, matrix);
r_phis[i].rotation += square_finder.best_angle;
mul_m2_v2(matrix, r_phis[i].translation);
r_phis[i].translation.x -= square_finder.best_bounds.xmin;
@ -1777,17 +1777,25 @@ class OverlapMerger {
sub_params.merge_overlap = false;
const float result = pack_islands(sub_islands, sub_params);
/* Must loop backwards! */
/* Must loop backwards, or we will miss sub-sub-islands. */
for (int64_t i = merge_trace.size() - 3; i >= 0; i -= 3) {
PackIsland *sub_a = merge_trace[i];
PackIsland *sub_b = merge_trace[i + 1];
PackIsland *merge = merge_trace[i + 2];
/* Copy `angle`, `pre_translate` and `pre_rotate` from merged island to sub islands. */
sub_a->angle = merge->angle;
sub_b->angle = merge->angle;
sub_a->pre_translate = merge->pre_translate;
sub_b->pre_translate = merge->pre_translate;
sub_a->pre_rotate_ = merge->pre_rotate_;
sub_b->pre_rotate_ = merge->pre_rotate_;
/* If the merged island is pinned, the sub-islands are also pinned to correct scaling. */
if (merge->pinned) {
sub_a->pinned = true;
sub_b->pinned = true;
}
delete merge;
}
@ -1823,8 +1831,24 @@ float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params
finalize_geometry(islands, params);
/* Count the number of islands which can scale and which can translate. */
int64_t can_scale_count = 0;
int64_t can_translate_count = 0;
for (const int64_t i : islands.index_range()) {
if (islands[i]->can_scale_(params)) {
can_scale_count++;
}
if (islands[i]->can_translate_(params)) {
can_translate_count++;
}
}
if (can_translate_count == 0) {
return 1.0f; /* Nothing to do, all islands are locked. */
}
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f &&
params.scale_to_fit)
can_scale_count > 0)
{
/* Uses a line search on scale. ~10x slower than other method. */
return pack_islands_margin_fraction(islands, params.margin, false, params);
@ -1837,28 +1861,24 @@ float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params
case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
margin = calc_margin_from_aabb_length_sum(islands, params);
break;
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
BLI_assert(params.margin == 0.0f); /* Other (slower) cases are handled above. */
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
/* Most other cases are handled above, unless pinning is involved. */
break;
default:
BLI_assert_unreachable();
}
/* TODO: Only line-search if *some* islands can scale and *some* are locked. */
switch (params.pin_method) {
case ED_UVPACK_PIN_LOCK_ALL:
case ED_UVPACK_PIN_LOCK_SCALE:
case ED_UVPACK_PIN_LOCK_ROTATION_SCALE:
return pack_islands_margin_fraction(islands, margin, true, params);
default:
break;
if (can_scale_count > 0 && can_scale_count != islands.size()) {
/* Search for the best scale parameter. (slow) */
return pack_islands_margin_fraction(islands, margin, true, params);
}
/* Either all of the islands can scale, or none of them can.
* In either case, we pack them all tight to the origin. */
blender::Array<uv_phi> phis(islands.size());
const float scale = 1.0f;
const float max_uv = pack_islands_scale_margin(islands, scale, margin, params, phis);
const float result = params.scale_to_fit ? 1.0f / max_uv : 1.0f;
const float result = can_scale_count > 0 ? 1.0f / max_uv : 1.0f;
for (const int64_t i : islands.index_range()) {
BLI_assert(result == 1.0f || islands[i]->can_scale_(params));
islands[i]->place_(scale, phis[i]);

View File

@ -87,7 +87,7 @@ void *GPU_debug_capture_scope_create(const char *name);
/**
* Used to declare the region within which GPU calls are captured when the scope is triggered.
*
* \param scope Pointer to capture scope object created with GPU_debug_capture_scope_create.
* \param scope: Pointer to capture scope object created with GPU_debug_capture_scope_create.
* \return True if the capture tool is actively capturing this scope when function is executed.
* Otherwise, False.
*/

View File

@ -178,6 +178,9 @@ bool Texture::init_view(GPUTexture *src_,
void Texture::usage_set(eGPUTextureUsage usage_flags)
{
gpu_image_usage_flags_ = usage_flags;
/* Metal: Texture clearing is done using frame-buffer clear. This has no performance impact. */
/* TODO(fclem): Move this to metal backend instead to avoid side effects in other back-ends. */
gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
}
/** \} */

View File

@ -1390,9 +1390,15 @@ bool MTLShader::bake_compute_pipeline_state(MTLContext *ctx)
}
/* Compile PSO. */
MTLComputePipelineDescriptor *desc = [[MTLComputePipelineDescriptor alloc] init];
desc.maxTotalThreadsPerThreadgroup = 1024;
desc.computeFunction = compute_function;
id<MTLComputePipelineState> pso = [ctx->device
newComputePipelineStateWithFunction:compute_function
error:&error];
newComputePipelineStateWithDescriptor:desc
options:MTLPipelineOptionNone
reflection:nullptr
error:&error];
if (error) {
NSLog(@"Failed to create PSO for compute shader: %s error %@\n", this->name, error);

View File

@ -142,7 +142,7 @@ VKStateManager &VKContext::state_manager_get()
/** \} */
/* -------------------------------------------------------------------- */
/** \name Framebuffer
/** \name Frame-buffer
* \{ */
void VKContext::activate_framebuffer(VKFrameBuffer &framebuffer)

View File

@ -33,9 +33,9 @@ class VKFrameBuffer : public FrameBuffer {
/**
* Should we flip the viewport to match Blenders coordinate system. We flip the viewport for
* offscreen framebuffers.
* off-screen frame-buffers.
*
* When two framebuffers are blitted we also check if the coordinate system should be flipped
* When two frame-buffers are blitted we also check if the coordinate system should be flipped
* during blitting.
*/
bool flip_viewport_ = false;

View File

@ -169,7 +169,7 @@ void VKPipeline::finalize(VKContext &context,
viewport_state.scissorCount = 1;
pipeline_create_info.pViewportState = &viewport_state;
/* Multisample state. */
/* Multi-sample state. */
VkPipelineMultisampleStateCreateInfo multisample_state = {};
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;

View File

@ -20,7 +20,7 @@ VKPipelineStateManager::VKPipelineStateManager()
depth_stencil_state = {};
depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
/* TODO should be extracted from current framebuffer and should not be done here and now. */
/* TODO should be extracted from current frame-buffer and should not be done here and now. */
/* When the attachments differ the state should be forced. */
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
@ -364,4 +364,4 @@ void VKPipelineStateManager::set_shadow_bias(const bool enable)
}
}
} // namespace blender::gpu
} // namespace blender::gpu

View File

@ -65,7 +65,7 @@ void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_se
continue;
}
if (0 == BLI_path_cmp_normalized(src, dst)) {
continue; /* Source and dest are the same. */
continue; /* Source and destination are the same. */
}
if (!BLI_file_ensure_parent_dir_exists(dst)) {
fprintf(stderr, "Can't make directory for '%s', not copying\n", dst);

View File

@ -103,8 +103,10 @@ static bool prim_path_valid(const char *path)
return true;
}
/* Perform validation of export parameter settings. Returns
* true if the paramters are valid; returns false otherwise. */
/**
* Perform validation of export parameter settings.
* \return true if the parameters are valid; returns false otherwise.
*/
static bool export_params_valid(const USDExportParams &params)
{
bool valid = true;

View File

@ -296,7 +296,7 @@ static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
Array<float> temp_knots(knots_num);
bke::curves::nurbs::calculate_knots(tot_points, mode, order, is_cyclic, temp_knots);
/* Knots should be the concatentation of all batched curves.
/* Knots should be the concatenation of all batched curves.
* https://graphics.pixar.com/usd/dev/api/class_usd_geom_nurbs_curves.html#details */
for (int i_knot = 0; i_knot < knots_num; i_knot++) {
knots.push_back(double(temp_knots[i_knot]));

Some files were not shown because too many files have changed in this diff Show More