Merge branch 'blender-v4.2-release'

This commit is contained in:
Brecht Van Lommel 2024-06-18 21:19:24 +02:00
commit a26fd603b0
24 changed files with 181 additions and 74 deletions

@ -196,7 +196,7 @@ ifndef DEPS_BUILD_DIR
endif
ifndef DEPS_INSTALL_DIR
DEPS_INSTALL_DIR:=$(shell dirname "$(BLENDER_DIR)")/lib/$(OS_LIBDIR)_$(CPU)
DEPS_INSTALL_DIR:=$(BLENDER_DIR)/lib/$(OS_LIBDIR)_$(CPU)
endif
# Set the LIBDIR, an empty string when not found.

@ -593,40 +593,70 @@ BoundBox Camera::viewplane_bounds_get()
* checks we need in a more clear and smart fashion? */
BoundBox bounds = BoundBox::empty;
const float max_aperture_size = aperture_ratio < 1.0f ? aperturesize / aperture_ratio :
aperturesize;
if (camera_type == CAMERA_PANORAMA) {
const float extend = max_aperture_size + nearclip;
if (use_spherical_stereo == false) {
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), nearclip);
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), extend);
}
else {
float half_eye_distance = interocular_distance * 0.5f;
bounds.grow(
make_float3(cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w),
nearclip);
extend);
}
}
else {
bounds.grow(transform_raster_to_world(0.0f, 0.0f));
bounds.grow(transform_raster_to_world(0.0f, (float)height));
bounds.grow(transform_raster_to_world((float)width, (float)height));
bounds.grow(transform_raster_to_world((float)width, 0.0f));
/* max_aperture_size = Max horizontal distance a ray travels from aperture edge to focus point.
* Scale that value based on the ratio between focaldistance and nearclip to figure out the
* horizontal distance the DOF ray will travel before reaching the nearclip plane, where it
* will start rendering from.
* In some cases (focus distance is close to camera, and nearclip plane is far from camera),
* this scaled value is larger than nearclip, in which case we add it to `extend` to extend the
* bounding box to account for these rays.
*
* ----------------- nearclip plane
* / scaled_horz_dof_ray, nearclip
* /
* /
* / horz_dof_ray, focaldistance
* /|
* / |
* / |
* / |
* ------ max_aperture_size, 0
* 0, 0
*/
const float scaled_horz_dof_ray = (max_aperture_size > 0.0f) ?
max_aperture_size * (nearclip / focaldistance) :
0.0f;
const float extend = max_aperture_size + max(nearclip, scaled_horz_dof_ray);
bounds.grow(transform_raster_to_world(0.0f, 0.0f), extend);
bounds.grow(transform_raster_to_world(0.0f, (float)height), extend);
bounds.grow(transform_raster_to_world((float)width, (float)height), extend);
bounds.grow(transform_raster_to_world((float)width, 0.0f), extend);
if (camera_type == CAMERA_PERSPECTIVE) {
/* Center point has the most distance in local Z axis,
* use it to construct bounding box/
*/
bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height));
bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height), extend);
}
}
return bounds;

@ -233,6 +233,7 @@ class ConstraintButtonsPanel:
layout.prop(con, "euler_order", text="Order")
layout.prop(con, "use_transform_limit")
layout.prop(con, "use_legacy_behavior")
self.space_template(layout, con, target=False, owner=True)
self.draw_influence(layout, con)

@ -1758,17 +1758,43 @@ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /
mat4_to_eulO(eul, rot_order, cob->matrix);
/* constraint data uses radians internally */
/* limiting of euler values... */
if (data->flag & LIMIT_XROT) {
eul[0] = clamp_angle(eul[0], data->xmin, data->xmax);
/* Limit the euler values. */
if (data->flag & LIMIT_ROT_LEGACY_BEHAVIOR) {
/* The legacy behavior, which just does a naive clamping of the angles as
* simple numbers. Since the input angles are always in the range [-180,
* 180] degrees due to being derived from matrix decomposition, this naive
* approach causes problems when rotations cross 180 degrees. Specifically,
* it results in unpredictable and unwanted rotation flips of the
* constrained objects/bones, especially when the constraint isn't in local
* space.
*
* The correct thing to do is a more sophisticated form of clamping that
* treats the angles as existing on a continuous loop, which is what the
* non-legacy behavior further below does. However, for backwards
* compatibility we are preserving this old behavior behind an option.
*
* See issues #117927 and #123105 for additional background. */
if (data->flag & LIMIT_XROT) {
eul[0] = clamp_f(eul[0], data->xmin, data->xmax);
}
if (data->flag & LIMIT_YROT) {
eul[1] = clamp_f(eul[1], data->ymin, data->ymax);
}
if (data->flag & LIMIT_ZROT) {
eul[2] = clamp_f(eul[2], data->zmin, data->zmax);
}
}
if (data->flag & LIMIT_YROT) {
eul[1] = clamp_angle(eul[1], data->ymin, data->ymax);
}
if (data->flag & LIMIT_ZROT) {
eul[2] = clamp_angle(eul[2], data->zmin, data->zmax);
else {
/* The correct, non-legacy behavior. */
if (data->flag & LIMIT_XROT) {
eul[0] = clamp_angle(eul[0], data->xmin, data->xmax);
}
if (data->flag & LIMIT_YROT) {
eul[1] = clamp_angle(eul[1], data->ymin, data->ymax);
}
if (data->flag & LIMIT_ZROT) {
eul[2] = clamp_angle(eul[2], data->zmin, data->zmax);
}
}
loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);

@ -203,7 +203,7 @@ static void scene_init_data(ID *id)
pset->brush[PE_BRUSH_CUT].strength = 1.0f;
}
STRNCPY(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
STRNCPY(scene->r.engine, RE_engine_id_BLENDER_EEVEE_NEXT);
STRNCPY(scene->r.pic, U.renderdir);

@ -17,6 +17,7 @@
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_defaults.h"
#include "DNA_light_types.h"
@ -4176,6 +4177,33 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 60) ||
(bmain->versionfile == 403 && !MAIN_VERSION_FILE_ATLEAST(bmain, 403, 3)))
{
/* Limit Rotation constraints from old files should use the legacy Limit
* Rotation behavior. */
LISTBASE_FOREACH (Object *, obj, &bmain->objects) {
LISTBASE_FOREACH (bConstraint *, constraint, &obj->constraints) {
if (constraint->type != CONSTRAINT_TYPE_ROTLIMIT) {
continue;
}
static_cast<bRotLimitConstraint *>(constraint->data)->flag |= LIMIT_ROT_LEGACY_BEHAVIOR;
}
if (!obj->pose) {
continue;
}
LISTBASE_FOREACH (bPoseChannel *, pbone, &obj->pose->chanbase) {
LISTBASE_FOREACH (bConstraint *, constraint, &pbone->constraints) {
if (constraint->type != CONSTRAINT_TYPE_ROTLIMIT) {
continue;
}
static_cast<bRotLimitConstraint *>(constraint->data)->flag |= LIMIT_ROT_LEGACY_BEHAVIOR;
}
}
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 403, 3)) {
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (BrushGpencilSettings *settings = brush->gpencil_settings) {

@ -51,6 +51,9 @@ void AmbientOcclusion::init()
data_.thickness_far = sce_eevee.fast_gi_thickness_far;
/* Size is multiplied by 2 because it is applied in NDC [-1..1] range. */
data_.pixel_size = float2(2.0f) / float2(inst_.film.render_extent_get());
ray_count_ = sce_eevee.fast_gi_ray_count;
step_count_ = sce_eevee.fast_gi_step_count;
}
void AmbientOcclusion::sync()
@ -60,7 +63,10 @@ void AmbientOcclusion::sync()
}
render_pass_ps_.init();
render_pass_ps_.shader_set(inst_.shaders.static_shader_get(AMBIENT_OCCLUSION_PASS));
GPUShader *sh = inst_.shaders.static_shader_get(AMBIENT_OCCLUSION_PASS);
render_pass_ps_.specialize_constant(sh, "ao_slice_count", ray_count_);
render_pass_ps_.specialize_constant(sh, "ao_step_count", step_count_);
render_pass_ps_.shader_set(sh);
render_pass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, &inst_.pipelines.utility_tx);
render_pass_ps_.bind_resources(inst_.uniform_data);

@ -29,6 +29,8 @@ class AmbientOcclusion {
class Instance &inst_;
bool render_pass_enabled_;
int ray_count_ = 0;
int step_count_ = 0;
AOData &data_;
PassSimple render_pass_ps_ = {"AO Render Pass"};

@ -253,6 +253,8 @@ void Film::init(const int2 &extent, const rcti *output_rect)
data_.scaling_factor = BKE_render_preview_pixel_size(&inst_.scene->r);
}
}
/* Sharpen the LODs (1.5x) to avoid TAA filtering causing over-blur (see #122941). */
data_.texture_lod_bias = 1.0f / (data_.scaling_factor * 1.5f);
}
{
rcti fallback_rect;

@ -449,13 +449,14 @@ struct FilmData {
float exposure_scale;
/** Scaling factor for scaled resolution rendering. */
int scaling_factor;
/** Software LOD bias to apply to when sampling texture inside the node-tree evaluation. */
float texture_lod_bias;
/** Film pixel filter radius. */
float filter_radius;
/** Precomputed samples. First in the table is the closest one. The rest is unordered. */
int samples_len;
/** Sum of the weights of all samples in the sample table. */
float samples_weight_total;
int _pad1;
int _pad2;
FilmSample samples[FILM_PRECOMP_SAMPLE_MAX];
};

@ -26,10 +26,8 @@ void main()
vec3 N = imageLoad(in_normal_img, ivec3(texel, in_normal_img_layer_index)).xyz;
vec3 vN = drw_normal_world_to_view(N);
vec3 noise;
noise.x = interlieved_gradient_noise(vec2(texel), 3.0, 0.0);
noise.yz = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER).rg;
noise = fract(noise + sampling_rng_3D_get(SAMPLING_AO_U));
vec4 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER);
noise = fract(noise + sampling_rng_3D_get(SAMPLING_AO_U).xyzx);
HorizonScanResult scan = horizon_scan_eval(vP,
vN,
@ -39,8 +37,8 @@ void main()
uniform_buf.ao.thickness_near,
uniform_buf.ao.thickness_far,
uniform_buf.ao.angle_bias,
2,
10,
ao_slice_count,
ao_step_count,
false,
true);

@ -43,8 +43,8 @@ void main()
vec3 vP = drw_point_screen_to_view(vec3(uv, depth));
vec3 vN = horizon_scan_sample_normal(uv);
vec3 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER).rgb;
noise = fract(noise + sampling_rng_3D_get(SAMPLING_AO_U));
vec4 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER);
noise = fract(noise + sampling_rng_3D_get(SAMPLING_AO_U).xyzx);
HorizonScanResult scan = horizon_scan_eval(vP,
vN,

@ -65,7 +65,7 @@ struct HorizonScanResult {
*/
HorizonScanResult horizon_scan_eval(vec3 vP,
vec3 vN,
vec3 noise,
vec4 noise,
vec2 pixel_size,
float search_distance,
float thickness_near,
@ -142,7 +142,7 @@ HorizonScanResult horizon_scan_eval(vec3 vP,
time += 1.0;
}
float lod = 1.0 + float(j) * uniform_buf.ao.lod_factor;
float lod = 1.0 + saturate(float(j) - noise.w) * uniform_buf.ao.lod_factor;
vec2 sample_uv = ssray.origin.xy + ssray.direction.xy * time;
float sample_depth = textureLod(hiz_tx, sample_uv * uniform_buf.hiz.uv_scale, lod).r;
@ -156,16 +156,12 @@ HorizonScanResult horizon_scan_eval(vec3 vP,
const float bias = 2.0 * 2.4e-7;
sample_depth += reversed ? -bias : bias;
vec3 vP_sample = drw_point_screen_to_view(vec3(sample_uv, sample_depth));
vec3 vP_sample_front = drw_point_screen_to_view(vec3(sample_uv, sample_depth));
vec3 vP_sample_back = vP_sample_front - vV * thickness_near;
float sample_distance;
vec3 vL_front = normalize_and_get_length(vP_sample - vP, sample_distance);
if (sample_distance > search_distance) {
continue;
}
vec3 vL_back = normalize_and_get_length((vP_sample - vV * thickness_near) - vP,
sample_distance);
vec3 vL_front = normalize_and_get_length(vP_sample_front - vP, sample_distance);
vec3 vL_back = normalize(vP_sample_back - vP);
if (sample_distance > search_distance) {
continue;
}

@ -9,8 +9,6 @@
#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl)
#define filmScalingFactor float(uniform_buf.film.scaling_factor)
vec3 g_emission;
vec3 g_transmittance;
float g_holdout;
@ -713,9 +711,9 @@ vec3 coordinate_incoming(vec3 P)
*
* \{ */
float film_scaling_factor_get()
float texture_lod_bias_get()
{
return float(uniform_buf.film.scaling_factor);
return uniform_buf.film.texture_lod_bias;
}
/** \} */

@ -13,6 +13,8 @@ GPU_SHADER_CREATE_INFO(eevee_ambient_occlusion_pass)
.push_constant(Type::INT, "in_normal_img_layer_index")
.image(1, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_ao_img")
.push_constant(Type::INT, "out_ao_img_layer_index")
.specialization_constant(Type::INT, "ao_slice_count", 2)
.specialization_constant(Type::INT, "ao_step_count", 8)
.additional_info("draw_view",
"eevee_shared",
"eevee_hiz_data",

@ -267,7 +267,7 @@ const char *ED_preview_collection_name(const ePreviewType pr_type)
static bool render_engine_supports_ray_visibility(const Scene *sce)
{
return !STREQ(sce->r.engine, RE_engine_id_BLENDER_EEVEE);
return !STREQ(sce->r.engine, RE_engine_id_BLENDER_EEVEE_NEXT);
}
static void switch_preview_collection_visibility(ViewLayer *view_layer, const ePreviewType pr_type)
@ -509,7 +509,7 @@ static Scene *preview_prepare_scene(
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
STRNCPY(sce->r.engine, RE_engine_id_BLENDER_EEVEE);
STRNCPY(sce->r.engine, RE_engine_id_BLENDER_EEVEE_NEXT);
}
if (id_type == ID_MA) {

@ -1580,7 +1580,7 @@ RenderEngineType *ED_view3d_engine_type(const Scene *scene, int drawtype)
*/
RenderEngineType *type = RE_engines_find(scene->r.engine);
if (drawtype == OB_MATERIAL && (type->flag & RE_USE_EEVEE_VIEWPORT)) {
return RE_engines_find(RE_engine_id_BLENDER_EEVEE);
return RE_engines_find(RE_engine_id_BLENDER_EEVEE_NEXT);
}
return type;
}
@ -2477,8 +2477,7 @@ bool ED_view3d_has_depth_buffer_updated(const Depsgraph *depsgraph, const View3D
bool is_viewport_preview_solid = v3d->shading.type == OB_SOLID;
bool is_viewport_preview_material = v3d->shading.type == OB_MATERIAL;
bool is_viewport_render_eevee = v3d->shading.type == OB_RENDER &&
(STREQ(engine_name, RE_engine_id_BLENDER_EEVEE) ||
STREQ(engine_name, RE_engine_id_BLENDER_EEVEE_NEXT));
(STREQ(engine_name, RE_engine_id_BLENDER_EEVEE_NEXT));
bool is_viewport_render_workbench = v3d->shading.type == OB_RENDER &&
STREQ(engine_name, RE_engine_id_BLENDER_WORKBENCH);
bool is_viewport_render_external_with_overlay = v3d->shading.type == OB_RENDER &&

@ -262,9 +262,10 @@ static OffsetIndices<int> recent_position_offsets(TransCustomData &custom_data,
}
/**
* Creates map of indices to `tc.data` representing curve in layout
* [L0, P0, R0, L1, P1, R1, L2,P2, R2], where [P0, P1, P2], [L0, L1, L2] and [R0, R1, R2] are
* positions, left handles and right handles respectively.
* Creates map of indices to `tc.data` representing the curves.
* For bezier curves it uses the layout [L0, P0, R0, L1, P1, R1, L2, P2, R2], where [P0, P1, P2],
* [L0, L1, L2] and [R0, R1, R2] are positions, left handles and right handles respectively.
* Other curve types just use the positions [P0, P1, ..., Pn] of the control points directly.
*/
static void fill_map(const CurveType curve_type,
const IndexRange curve_points,
@ -272,24 +273,22 @@ static void fill_map(const CurveType curve_type,
const int handles_offset,
MutableSpan<int> map)
{
const int attr_num = (curve_type == CURVE_TYPE_BEZIER) ? 3 : 1;
const int left_handle_index = handles_offset + position_offsets_in_td[1].start();
const int position_index = curve_points.start() + position_offsets_in_td[0].start();
const int right_handle_index = handles_offset + position_offsets_in_td[2].start();
std::array<int, 3> first_per_attr = {curve_type == CURVE_TYPE_BEZIER ? left_handle_index :
position_index,
/* Next two unused for non Bezier curves. */
position_index,
right_handle_index};
threading::parallel_for(curve_points.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
for (const int attr : IndexRange(attr_num)) {
map[i * attr_num + attr] = first_per_attr[attr] + i;
if (curve_type == CURVE_TYPE_BEZIER) {
const int left_handle_index = handles_offset + position_offsets_in_td[1].start();
const int right_handle_index = handles_offset + position_offsets_in_td[2].start();
std::array<int, 3> first_per_attr = {left_handle_index, position_index, right_handle_index};
threading::parallel_for(curve_points.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
for (const int attr : IndexRange(3)) {
map[i * 3 + attr] = first_per_attr[attr] + i;
}
}
}
});
});
}
else {
array_utils::fill_index_range(map, position_index);
}
}
} // namespace blender::ed::transform::curves

@ -875,6 +875,12 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
if (GPUPass *default_pass = pass_replacement_cb ? pass_replacement_cb(thunk, mat) : nullptr) {
mat->pass = default_pass;
GPU_pass_acquire(mat->pass);
/** WORKAROUND:
* The node tree code is never executed in default replaced passes,
* but the GPU validation will still complain if the node tree UBO is not bound.
* So we create a dummy UBO with (at least) the size of the default material one (192 bytes).
* We allocate 256 bytes to leave some room for future changes. */
mat->ubo = GPU_uniformbuf_create_ex(256, nullptr, "Dummy UBO");
}
else {
/* Create source code and search pass cache for an already compiled version. */

@ -57,9 +57,8 @@ void point_map_to_tube(vec3 vin, out vec3 vout)
void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
{
#ifdef GPU_FRAGMENT_SHADER
vec2 scaling_factor = vec2(film_scaling_factor_get());
vec2 dx = dFdx(co.xy) / scaling_factor;
vec2 dy = dFdy(co.xy) / scaling_factor;
vec2 dx = dFdx(co.xy) * texture_lod_bias_get();
vec2 dy = dFdy(co.xy) * texture_lod_bias_get();
color = safe_color(textureGrad(ima, co.xy, dx, dy));
#else

@ -1067,6 +1067,11 @@ typedef enum eRotLimit_Flags {
LIMIT_XROT = (1 << 0),
LIMIT_YROT = (1 << 1),
LIMIT_ZROT = (1 << 2),
/* Use the legacy behavior of the Limit Rotation constraint. See the
* implementation of `rotlimit_evaluate()` in constraint.cc for more
* details. */
LIMIT_ROT_LEGACY_BEHAVIOR = (1 << 3),
} eRotLimit_Flags;
/* distance limit constraint */

@ -2690,6 +2690,14 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
prop, "Affect Transform", "Transform tools are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "use_legacy_behavior", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", LIMIT_ROT_LEGACY_BEHAVIOR);
RNA_def_property_ui_text(
prop,
"Legacy Behavior",
"Use the old semi-broken behavior that doesn't understand that rotations loop around");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false);
}

@ -2074,7 +2074,7 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, const bool
char scene_engine[32];
STRNCPY(scene_engine, re->r.engine);
if (use_eevee_for_freestyle_render(re)) {
change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE);
change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE_NEXT);
}
RE_engine_render(re, false);

@ -42,6 +42,7 @@ def setup():
eevee.volumetric_end = 50.0
eevee.volumetric_samples = 128
eevee.use_volumetric_shadows = True
eevee.clamp_volume_indirect = 0.0
# Motion Blur
if scene.render.use_motion_blur: